am 825f29b1: Merge from jb-mr1.1-dev
# Via Jean-Baptiste Queru
* commit '825f29b1c8f0c420af5dc6b05f0dbbd5b1ec36bf':
diff --git a/adb/Android.mk b/adb/Android.mk
index 32dd95a..bc8315e 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -16,7 +16,7 @@
ifeq ($(HOST_OS),linux)
USB_SRCS := usb_linux.c
EXTRA_SRCS := get_my_path_linux.c
- LOCAL_LDLIBS += -lrt -ldl -lpthread
+ LOCAL_LDLIBS += -lrt -lncurses -lpthread
endif
ifeq ($(HOST_OS),darwin)
@@ -139,7 +139,7 @@
ifneq ($(SDK_ONLY),true)
include $(CLEAR_VARS)
-LOCAL_LDLIBS := -lrt -ldl -lpthread
+LOCAL_LDLIBS := -lrt -lncurses -lpthread
LOCAL_SRC_FILES := \
adb.c \
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index b53bc44..d9aa09c 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -117,34 +117,7 @@
or even any one of the local services described below.
-<host-prefix>:forward:norebind:<local>;<remote>
- Same as <host-prefix>:forward:<local>;<remote> except that it will
- fail it there is already a forward connection from <local>.
- Used to implement 'adb forward --no-rebind <local> <remote>'
-
-<host-prefix>:killforward:<local>
- Remove any existing forward local connection from <local>.
- This is used to implement 'adb forward --remove <local>'
-
-<host-prefix>:killforward-all
- Remove all forward network connections.
- This is used to implement 'adb forward --remove-all'.
-
-<host-prefix>:list-forward
- List all existing forward connections from this server.
- This returns something that looks like the following:
-
- <hex4>: The length of the payload, as 4 hexadecimal chars.
- <payload>: A series of lines of the following format:
-
- <serial> " " <local> " " <remote> "\n"
-
- Where <serial> is a device serial number.
- <local> is the host-specific endpoint (e.g. tcp:9000).
- <remote> is the device-specific endpoint.
-
- Used to implement 'adb forward --list'.
LOCAL SERVICES:
diff --git a/adb/adb.c b/adb/adb.c
index 92436da..07bfbe5 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -25,7 +25,6 @@
#include <string.h>
#include <time.h>
#include <sys/time.h>
-#include <stdint.h>
#include "sysdeps.h"
#include "adb.h"
@@ -47,7 +46,6 @@
#endif
int HOST = 0;
-int gListenAll = 0;
static int auth_enabled = 0;
@@ -703,13 +701,7 @@
if(!strncmp("tcp:", name, 4)){
int ret;
port = atoi(name + 4);
-
- if (gListenAll > 0) {
- ret = socket_inaddr_any_server(port, SOCK_STREAM);
- } else {
- ret = socket_loopback_server(port, SOCK_STREAM);
- }
-
+ ret = socket_loopback_server(port, SOCK_STREAM);
return ret;
}
#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
@@ -730,90 +722,24 @@
return -1;
}
-// Write a single line describing a listener to a user-provided buffer.
-// Appends a trailing zero, even in case of truncation, but the function
-// returns the full line length.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
- // Format is simply:
- //
- // <device-serial> " " <local-name> " " <remote-name> "\n"
- //
- int local_len = strlen(l->local_name);
- int connect_len = strlen(l->connect_to);
- int serial_len = strlen(l->transport->serial);
-
- if (buffer != NULL) {
- snprintf(buffer, buffer_len, "%s %s %s\n",
- l->transport->serial, l->local_name, l->connect_to);
- }
- // NOTE: snprintf() on Windows returns -1 in case of truncation, so
- // return the computed line length instead.
- return local_len + connect_len + serial_len + 3;
-}
-
-// Write the list of current listeners (network redirections) into a
-// user-provided buffer. Appends a trailing zero, even in case of
-// trunctaion, but return the full size in bytes.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listeners(char* buf, size_t buflen)
-{
- alistener* l;
- int result = 0;
- for (l = listener_list.next; l != &listener_list; l = l->next) {
- // Ignore special listeners like those for *smartsocket*
- if (l->connect_to[0] == '*')
- continue;
- int len = format_listener(l, buf, buflen);
- // Ensure there is space for the trailing zero.
- result += len;
- if (buf != NULL) {
- buf += len;
- buflen -= len;
- if (buflen <= 0)
- break;
- }
- }
- return result;
-}
-
-static int remove_listener(const char *local_name, atransport* transport)
+static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
{
alistener *l;
for (l = listener_list.next; l != &listener_list; l = l->next) {
- if (!strcmp(local_name, l->local_name)) {
- listener_disconnect(l, l->transport);
+ if (!strcmp(local_name, l->local_name) &&
+ !strcmp(connect_to, l->connect_to) &&
+ l->transport && l->transport == transport) {
+
+ listener_disconnect(l, transport);
return 0;
}
}
+
return -1;
}
-static void remove_all_listeners(void)
-{
- alistener *l, *l_next;
- for (l = listener_list.next; l != &listener_list; l = l_next) {
- l_next = l->next;
- // Never remove smart sockets.
- if (l->connect_to[0] == '*')
- continue;
- listener_disconnect(l, l->transport);
- }
-}
-
-// error/status codes for install_listener.
-typedef enum {
- INSTALL_STATUS_OK = 0,
- INSTALL_STATUS_INTERNAL_ERROR = -1,
- INSTALL_STATUS_CANNOT_BIND = -2,
- INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
-
-static install_status_t install_listener(const char *local_name,
- const char *connect_to,
- atransport* transport,
- int no_rebind)
+static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
{
alistener *l;
@@ -825,17 +751,12 @@
/* can't repurpose a smartsocket */
if(l->connect_to[0] == '*') {
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- /* can't repurpose a listener if 'no_rebind' is true */
- if (no_rebind) {
- return INSTALL_STATUS_CANNOT_REBIND;
+ return -1;
}
cto = strdup(connect_to);
if(cto == 0) {
- return INSTALL_STATUS_INTERNAL_ERROR;
+ return -1;
}
//printf("rebinding '%s' to '%s'\n", local_name, connect_to);
@@ -846,7 +767,7 @@
l->transport = transport;
add_transport_disconnect(l->transport, &l->disconnect);
}
- return INSTALL_STATUS_OK;
+ return 0;
}
}
@@ -883,11 +804,11 @@
l->disconnect.func = listener_disconnect;
add_transport_disconnect(transport, &l->disconnect);
}
- return INSTALL_STATUS_OK;
+ return 0;
nomem:
fatal("cannot allocate listener");
- return INSTALL_STATUS_INTERNAL_ERROR;
+ return 0;
}
#ifdef HAVE_WIN32_PROC
@@ -992,7 +913,6 @@
/* message since the pipe handles must be inheritable, we use a */
/* security attribute */
HANDLE pipe_read, pipe_write;
- HANDLE stdout_handle, stderr_handle;
SECURITY_ATTRIBUTES sa;
STARTUPINFO startup;
PROCESS_INFORMATION pinfo;
@@ -1012,26 +932,6 @@
SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
- /* Some programs want to launch an adb command and collect its output by
- * calling CreateProcess with inheritable stdout/stderr handles, then
- * using read() to get its output. When this happens, the stdout/stderr
- * handles passed to the adb client process will also be inheritable.
- * When starting the adb server here, care must be taken to reset them
- * to non-inheritable.
- * Otherwise, something bad happens: even if the adb command completes,
- * the calling process is stuck while read()-ing from the stdout/stderr
- * descriptors, because they're connected to corresponding handles in the
- * adb server process (even if the latter never uses/writes to them).
- */
- stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
- stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
- if (stdout_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
- }
- if (stderr_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
- }
-
ZeroMemory( &startup, sizeof(startup) );
startup.cb = sizeof(startup);
startup.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
@@ -1108,10 +1008,8 @@
dup2(fd[1], STDERR_FILENO);
adb_close(fd[1]);
- char str_port[30];
- snprintf(str_port, sizeof(str_port), "%d", server_port);
// child process
- int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+ int result = execl(path, "adb", "fork-server", "server", NULL);
// this should not return
fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
} else {
@@ -1215,7 +1113,7 @@
char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+ if(install_listener(local_name, "*smartsocket*", NULL)) {
exit(1);
}
#else
@@ -1282,7 +1180,7 @@
} else {
char local_name[30];
build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
+ if(install_listener(local_name, "*smartsocket*", NULL)) {
exit(1);
}
}
@@ -1576,63 +1474,24 @@
}
#endif // ADB_HOST
- if(!strcmp(service,"list-forward")) {
- // Create the list of forward redirections.
- char header[9];
- int buffer_size = format_listeners(NULL, 0);
- // Add one byte for the trailing zero.
- char* buffer = malloc(buffer_size+1);
- (void) format_listeners(buffer, buffer_size+1);
- snprintf(header, sizeof header, "OKAY%04x", buffer_size);
- writex(reply_fd, header, 8);
- writex(reply_fd, buffer, buffer_size);
- free(buffer);
- return 0;
- }
-
- if (!strcmp(service,"killforward-all")) {
- remove_all_listeners();
- adb_write(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- if(!strncmp(service,"forward:",8) ||
- !strncmp(service,"killforward:",12)) {
+ if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
char *local, *remote, *err;
int r;
atransport *transport;
int createForward = strncmp(service,"kill",4);
- int no_rebind = 0;
- local = strchr(service, ':') + 1;
-
- // Handle forward:norebind:<local>... here
- if (createForward && !strncmp(local, "norebind:", 9)) {
- no_rebind = 1;
- local = strchr(local, ':') + 1;
+ local = service + (createForward ? 8 : 12);
+ remote = strchr(local,';');
+ if(remote == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 0;
}
- remote = strchr(local,';');
-
- if (createForward) {
- // Check forward: parameter format: '<local>;<remote>'
- if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
- } else {
- // Check killforward: parameter format: '<local>'
- if (local[0] == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
+ *remote++ = 0;
+ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 0;
}
transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
@@ -1642,9 +1501,9 @@
}
if (createForward) {
- r = install_listener(local, remote, transport, no_rebind);
+ r = install_listener(local, remote, transport);
} else {
- r = remove_listener(local, transport);
+ r = remove_listener(local, remote, transport);
}
if(r == 0) {
/* 1st OKAY is connect, 2nd OKAY is status */
@@ -1653,18 +1512,7 @@
}
if (createForward) {
- const char* message;
- switch (r) {
- case INSTALL_STATUS_CANNOT_BIND:
- message = "cannot bind to socket";
- break;
- case INSTALL_STATUS_CANNOT_REBIND:
- message = "cannot rebind existing socket";
- break;
- default:
- message = "internal error";
- }
- sendfailmsg(reply_fd, message);
+ sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
} else {
sendfailmsg(reply_fd, "cannot remove listener");
}
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 8340738..9a812f0 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -17,7 +17,6 @@
static const char* __adb_serial = NULL;
static int __adb_server_port = DEFAULT_ADB_PORT;
-static const char* __adb_server_name = NULL;
void adb_set_transport(transport_type type, const char* serial)
{
@@ -30,11 +29,6 @@
__adb_server_port = server_port;
}
-void adb_set_tcp_name(const char* hostname)
-{
- __adb_server_name = hostname;
-}
-
int adb_get_emulator_console_port(void)
{
const char* serial = __adb_serial;
@@ -187,11 +181,7 @@
}
snprintf(tmp, sizeof tmp, "%04x", len);
- if (__adb_server_name)
- fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
- else
- fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
-
+ fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
if(fd < 0) {
strcpy(__adb_error, "cannot connect to daemon");
return -2;
@@ -222,10 +212,7 @@
int fd = _adb_connect("host:version");
D("adb_connect: service %s\n", service);
- if(fd == -2 && __adb_server_name) {
- fprintf(stderr,"** Cannot start server on remote host\n");
- return fd;
- } else if(fd == -2) {
+ if(fd == -2) {
fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
__adb_server_port);
start_server:
@@ -279,7 +266,7 @@
fd = _adb_connect(service);
if(fd == -2) {
- fprintf(stderr,"** daemon still not running\n");
+ fprintf(stderr,"** daemon still not running");
}
D("adb_connect: return fd %d\n", fd);
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 0ec47ca..40ab189 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -29,10 +29,6 @@
*/
void adb_set_tcp_specifics(int server_port);
-/* Set TCP Hostname of the transport to use
-*/
-void adb_set_tcp_name(const char* hostname);
-
/* Return the console port of the currently connected emulator (if any)
* of -1 if there is no emulator, and -2 if there is more than one.
* assumes adb_set_transport() was alled previously...
diff --git a/adb/commandline.c b/adb/commandline.c
index cbe4616..24cbb5a 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -46,7 +46,6 @@
int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
static const char *gProductOutPath = NULL;
-extern int gListenAll;
static char *product_file(const char *extra)
{
@@ -81,7 +80,6 @@
fprintf(stderr,
"\n"
- " -a - directs adb to listen on all interfaces for a connection\n"
" -d - directs command to the only connected USB device\n"
" returns an error if more than one USB device is present.\n"
" -e - directs command to the only running emulator.\n"
@@ -95,8 +93,6 @@
" If -p is not specified, the ANDROID_PRODUCT_OUT\n"
" environment variable is used, which must\n"
" be an absolute path.\n"
- " -H - Name of adb server host (default: localhost)\n"
- " -P - Port of adb server (default: 5037)\n"
" devices [-l] - list all connected devices\n"
" ('-l' will also list device qualifiers)\n"
" connect <host>[:<port>] - connect to a device via TCP/IP\n"
@@ -116,9 +112,6 @@
" adb shell <command> - run remote shell command\n"
" adb emu <command> - run emulator console command\n"
" adb logcat [ <filter-spec> ] - View device log\n"
- " adb forward --list - list all forward socket connections.\n"
- " the format is a list of lines with the following format:\n"
- " <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
" adb forward <local> <remote> - forward socket connections\n"
" forward specs are one of: \n"
" tcp:<port>\n"
@@ -127,11 +120,6 @@
" localfilesystem:<unix domain socket name>\n"
" dev:<character device name>\n"
" jdwp:<process pid> (remote only)\n"
- " adb forward --no-rebind <local> <remote>\n"
- " - same as 'adb forward <local> <remote>' but fails\n"
- " if <local> is already forwarded\n"
- " adb forward --remove <local> - remove a specific forward socket connection\n"
- " adb forward --remove-all - remove all forward socket connections\n"
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
" adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
" - push this package file to the device and install it\n"
@@ -950,9 +938,9 @@
int server_port = DEFAULT_ADB_PORT;
if (server_port_str && strlen(server_port_str) > 0) {
server_port = (int) strtol(server_port_str, NULL, 0);
- if (server_port <= 0 || server_port > 65535) {
+ if (server_port <= 0) {
fprintf(stderr,
- "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
+ "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number. Got \"%s\"\n",
server_port_str);
return usage();
}
@@ -998,42 +986,6 @@
ttype = kTransportUsb;
} else if (!strcmp(argv[0],"-e")) {
ttype = kTransportLocal;
- } else if (!strcmp(argv[0],"-a")) {
- gListenAll = 1;
- } else if(!strncmp(argv[0], "-H", 2)) {
- const char *hostname = NULL;
- if (argv[0][2] == '\0') {
- if (argc < 2) return usage();
- hostname = argv[1];
- argc--;
- argv++;
- } else {
- hostname = argv[0] + 2;
- }
- adb_set_tcp_name(hostname);
-
- } else if(!strncmp(argv[0], "-P", 2)) {
- if (argv[0][2] == '\0') {
- if (argc < 2) return usage();
- server_port_str = argv[1];
- argc--;
- argv++;
- } else {
- server_port_str = argv[0] + 2;
- }
- if (strlen(server_port_str) > 0) {
- server_port = (int) strtol(server_port_str, NULL, 0);
- if (server_port <= 0 || server_port > 65535) {
- fprintf(stderr,
- "adb: port number must be a positive number less than 65536. Got \"%s\"\n",
- server_port_str);
- return usage();
- }
- } else {
- fprintf(stderr,
- "adb: port number must be a positive number less than 65536. Got empty string.\n");
- return usage();
- }
} else {
/* out of recognized modifiers and flags */
break;
@@ -1271,85 +1223,16 @@
}
if(!strcmp(argv[0], "forward")) {
- char host_prefix[64];
- char remove = 0;
- char remove_all = 0;
- char list = 0;
- char no_rebind = 0;
-
- // Parse options here.
- while (argc > 1 && argv[1][0] == '-') {
- if (!strcmp(argv[1], "--list"))
- list = 1;
- else if (!strcmp(argv[1], "--remove"))
- remove = 1;
- else if (!strcmp(argv[1], "--remove-all"))
- remove_all = 1;
- else if (!strcmp(argv[1], "--no-rebind"))
- no_rebind = 1;
- else {
- return usage();
- }
- argc--;
- argv++;
- }
-
- // Ensure we can only use one option at a time.
- if (list + remove + remove_all + no_rebind > 1) {
- return usage();
- }
-
- // Determine the <host-prefix> for this command.
+ if(argc != 3) return usage();
if (serial) {
- snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
- serial);
+ snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
} else if (ttype == kTransportUsb) {
- snprintf(host_prefix, sizeof host_prefix, "host-usb");
+ snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
} else if (ttype == kTransportLocal) {
- snprintf(host_prefix, sizeof host_prefix, "host-local");
+ snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
} else {
- snprintf(host_prefix, sizeof host_prefix, "host");
+ snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
}
-
- // Implement forward --list
- if (list) {
- if (argc != 1)
- return usage();
- snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
- char* forwards = adb_query(buf);
- if (forwards == NULL) {
- fprintf(stderr, "error: %s\n", adb_error());
- return 1;
- }
- printf("%s", forwards);
- free(forwards);
- return 0;
- }
-
- // Implement forward --remove-all
- else if (remove_all) {
- if (argc != 1)
- return usage();
- snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
- }
-
- // Implement forward --remove <local>
- else if (remove) {
- if (argc != 2)
- return usage();
- snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
- }
- // Or implement one of:
- // forward <local> <remote>
- // forward --no-rebind <local> <remote>
- else
- {
- if (argc != 3)
- return usage();
- const char* command = no_rebind ? "forward:norebind:" : "forward";
- snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
- }
-
if(adb_command(buf)) {
fprintf(stderr,"error: %s\n", adb_error());
return 1;
diff --git a/adb/services.c b/adb/services.c
index 54d21a8..495a083 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -202,7 +202,7 @@
int c;
for(;;) {
- r = adb_read(fd, buf, 4096);
+ r = read(fd, buf, 4096);
if(r == 0) goto done;
if(r < 0) {
if(errno == EINTR) continue;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0252ef3..66b60cc 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -275,22 +275,6 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
-#include <unistd.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
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
@@ -326,7 +310,7 @@
{
if ((options & O_CREAT) == 0)
{
- return TEMP_FAILURE_RETRY( open(path, options) );
+ return open(path, options);
}
else
{
@@ -335,19 +319,19 @@
va_start( args, options );
mode = va_arg( args, int );
va_end( args );
- return TEMP_FAILURE_RETRY( open( path, options, mode ) );
+ return open(path, options, mode);
}
}
static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
{
- return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
+ return open( pathname, options, mode );
}
static __inline__ int adb_open( const char* pathname, int options )
{
- int fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
+ int fd = open( pathname, options );
if (fd < 0)
return -1;
close_on_exec( fd );
@@ -373,7 +357,7 @@
static __inline__ int adb_read(int fd, void* buf, size_t len)
{
- return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
+ return read(fd, buf, len);
}
#undef read
@@ -381,7 +365,7 @@
static __inline__ int adb_write(int fd, const void* buf, size_t len)
{
- return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
+ return write(fd, buf, len);
}
#undef write
#define write ___xxx_write
@@ -402,7 +386,7 @@
static __inline__ int adb_creat(const char* path, int mode)
{
- int fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
+ int fd = creat(path, mode);
if ( fd < 0 )
return -1;
@@ -417,7 +401,7 @@
{
int fd;
- fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
+ fd = accept(serverfd, addr, addrlen);
if (fd >= 0)
close_on_exec(fd);
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 2105b16..d41c42c 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -781,7 +781,7 @@
void disable_tcp_nagle(int fd)
{
FH fh = _fh_from_int(fd);
- int on = 1;
+ int on;
if ( !fh || fh->clazz != &_fh_socket_class )
return;
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index e48b9af..15083f4 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -23,11 +23,13 @@
LOCAL_CFLAGS += -DWITH_VFP_D32
endif # ARCH_ARM_HAVE_VFP_D32
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libc \
- libcorkscrew \
- libselinux
+LOCAL_SHARED_LIBRARIES := libcutils libc libcorkscrew
+
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index ba76e7d..62f7f32 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -125,9 +125,10 @@
char task_path[64];
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
DIR* d = opendir(task_path);
- if (d != NULL) {
- struct dirent* de = NULL;
- while ((de = readdir(d)) != NULL) {
+ if (d) {
+ struct dirent debuf;
+ struct dirent *de;
+ while (!readdir_r(d, &debuf, &de) && de) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
continue;
}
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 74eaa49..00652e9 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -20,7 +20,6 @@
void crash1(void);
void crashnostack(void);
void maybeabort(void);
-int do_action(const char* arg);
static void debuggerd_connect()
{
@@ -75,46 +74,24 @@
return 0;
}
-static void* thread_callback(void* raw_arg)
-{
- return (void*) do_action((const char*) raw_arg);
-}
-
-int do_action_on_thread(const char* arg)
-{
- pthread_t t;
- pthread_create(&t, NULL, thread_callback, (void*) arg);
- void* result = NULL;
- pthread_join(t, &result);
- return (int) result;
-}
-
-int do_action(const char* arg)
-{
- if(!strncmp(arg, "thread-", strlen("thread-"))) {
- return do_action_on_thread(arg + strlen("thread-"));
- }
-
- if(!strcmp(arg,"nostack")) crashnostack();
- if(!strcmp(arg,"ctest")) return ctest();
- if(!strcmp(arg,"exit")) exit(1);
- if(!strcmp(arg,"abort")) maybeabort();
-
- pthread_t thr;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&thr, &attr, test_thread, 0);
- while(1) sleep(1);
-}
-
int main(int argc, char **argv)
{
- fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
+ pthread_t thr;
+ pthread_attr_t attr;
+
+ fprintf(stderr,"crasher: " __TIME__ "!@\n");
fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
if(argc > 1) {
- return do_action(argv[1]);
+ if(!strcmp(argv[1],"nostack")) crashnostack();
+ if(!strcmp(argv[1],"ctest")) return ctest();
+ if(!strcmp(argv[1],"exit")) exit(1);
+ if(!strcmp(argv[1],"abort")) maybeabort();
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&thr, &attr, test_thread, 0);
+ while(1) sleep(1);
} else {
crash1();
// *((int*) 0) = 42;
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index e8b3e24..592f4f2 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -35,7 +35,9 @@
#include <corkscrew/demangle.h>
#include <corkscrew/backtrace.h>
+#ifdef HAVE_SELINUX
#include <selinux/android.h>
+#endif
#include "machine.h"
#include "tombstone.h"
@@ -84,7 +86,6 @@
static const char *get_sigcode(int signo, int code)
{
- // Try the signal-specific codes...
switch (signo) {
case SIGILL:
switch (code) {
@@ -123,31 +124,7 @@
case SEGV_ACCERR: return "SEGV_ACCERR";
}
break;
- case SIGTRAP:
- switch (code) {
- case TRAP_BRKPT: return "TRAP_BRKPT";
- case TRAP_TRACE: return "TRAP_TRACE";
- }
- break;
}
- // Then the other codes...
- switch (code) {
- case SI_USER: return "SI_USER";
-#if defined(SI_KERNEL)
- case SI_KERNEL: return "SI_KERNEL";
-#endif
- case SI_QUEUE: return "SI_QUEUE";
- case SI_TIMER: return "SI_TIMER";
- case SI_MESGQ: return "SI_MESGQ";
- case SI_ASYNCIO: return "SI_ASYNCIO";
-#if defined(SI_SIGIO)
- case SI_SIGIO: return "SI_SIGIO";
-#endif
-#if defined(SI_TKILL)
- case SI_TKILL: return "SI_TKILL";
-#endif
- }
- // Then give up...
return "?";
}
@@ -350,18 +327,6 @@
}
}
-static void dump_map(log_t* log, map_info_t* m, const char* what) {
- if (m != NULL) {
- _LOG(log, false, " %08x-%08x %c%c%c %s\n", m->start, m->end,
- m->is_readable ? 'r' : '-',
- m->is_writable ? 'w' : '-',
- m->is_executable ? 'x' : '-',
- m->name);
- } else {
- _LOG(log, false, " (no %s)\n", what);
- }
-}
-
static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid) {
siginfo_t si;
memset(&si, 0, sizeof(si));
@@ -408,9 +373,21 @@
* Show "next" then "match" then "prev" so that the addresses appear in
* ascending order (like /proc/pid/maps).
*/
- dump_map(log, next, "map below");
- dump_map(log, map, "map for address");
- dump_map(log, prev, "map above");
+ if (next != NULL) {
+ _LOG(log, false, " %08x-%08x %s\n", next->start, next->end, next->name);
+ } else {
+ _LOG(log, false, " (no map below)\n");
+ }
+ if (map != NULL) {
+ _LOG(log, false, " %08x-%08x %s\n", map->start, map->end, map->name);
+ } else {
+ _LOG(log, false, " (no map for address)\n");
+ }
+ if (prev != NULL) {
+ _LOG(log, false, " %08x-%08x %s\n", prev->start, prev->end, prev->name);
+ } else {
+ _LOG(log, false, " (no map above)\n");
+ }
}
static void dump_thread(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
@@ -439,8 +416,9 @@
}
bool detach_failed = false;
- struct dirent* de;
- while ((de = readdir(d)) != NULL) {
+ struct dirent debuf;
+ struct dirent *de;
+ while (!readdir_r(d, &debuf, &de) && de) {
/* Ignore "." and ".." */
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
continue;
@@ -718,10 +696,12 @@
mkdir(TOMBSTONE_DIR, 0755);
chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
+#ifdef HAVE_SELINUX
if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
*detach_failed = false;
return NULL;
}
+#endif
int fd;
char* path = find_and_open_tombstone(&fd);
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5025dae..92e9219 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -57,7 +57,9 @@
libz
ifneq ($(HOST_OS),windows)
+ifeq ($(HAVE_SELINUX), true)
LOCAL_STATIC_LIBRARIES += libselinux
+endif # HAVE_SELINUX
endif # HOST_OS != windows
include $(BUILD_HOST_EXECUTABLE)
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 8d46991..7a55260 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -29,7 +29,6 @@
#include "fastboot.h"
#include "make_ext4fs.h"
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -46,6 +45,8 @@
#include <sys/mman.h>
#endif
+extern struct fs_info info;
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
double now()
@@ -301,7 +302,10 @@
#else
fd = fileno(tmpfile());
#endif
- make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
+ /* reset ext4fs info so we can be called multiple times */
+ reset_ext4fs_info();
+ info.len = image->partition_size;
+ make_ext4fs_internal(fd, NULL, NULL, NULL, 0, 1, 0, 0, 0, NULL);
fstat(fd, &st);
image->image_size = st.st_size;
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index e51c9cf..99adb81 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -173,7 +173,7 @@
* then return an empty buffer. This effectively ignores lines that are too long.
* On EOF, return null.
*/
-static char *fs_getline(char *buf, int size, FILE *file)
+static char *getline(char *buf, int size, FILE *file)
{
int cnt = 0;
int eof = 0;
@@ -247,7 +247,7 @@
}
entries = 0;
- while (fs_getline(line, sizeof(line), fstab_file)) {
+ while (getline(line, sizeof(line), fstab_file)) {
/* if the last character is a newline, shorten the string by 1 byte */
len = strlen(line);
if (line[len - 1] == '\n') {
@@ -274,7 +274,7 @@
fseek(fstab_file, 0, SEEK_SET);
cnt = 0;
- while (fs_getline(line, sizeof(line), fstab_file)) {
+ while (getline(line, sizeof(line), fstab_file)) {
/* if the last character is a newline, shorten the string by 1 byte */
len = strlen(line);
if (line[len - 1] == '\n') {
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
index c9b241d..ea1d35f 100644
--- a/include/corkscrew/map_info.h
+++ b/include/corkscrew/map_info.h
@@ -32,7 +32,6 @@
uintptr_t start;
uintptr_t end;
bool is_readable;
- bool is_writable;
bool is_executable;
void* data; // arbitrary data associated with the map by the user, initially NULL
char name[];
@@ -47,10 +46,9 @@
/* Finds the memory map that contains the specified address. */
const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr);
-/* Returns true if the addr is in a readable map. */
+/* Returns true if the addr is in an readable map. */
bool is_readable_map(const map_info_t* milist, uintptr_t addr);
-/* Returns true if the addr is in a writable map. */
-bool is_writable_map(const map_info_t* milist, uintptr_t addr);
+
/* Returns true if the addr is in an executable map. */
bool is_executable_map(const map_info_t* milist, uintptr_t addr);
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
index 795afd3..16fe512 100644
--- a/include/cutils/atomic-arm.h
+++ b/include/cutils/atomic-arm.h
@@ -20,78 +20,72 @@
#include <stdint.h>
#include <machine/cpu-features.h>
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+extern inline void android_compiler_barrier(void)
{
__asm__ __volatile__ ("" : : : "memory");
}
#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
android_compiler_barrier();
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_compiler_barrier();
}
#elif defined(__ARM_HAVE_DMB)
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
__asm__ __volatile__ ("dmb" : : : "memory");
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
__asm__ __volatile__ ("dmb st" : : : "memory");
}
#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory");
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_memory_barrier();
}
#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
typedef void (kuser_memory_barrier)(void);
(*(kuser_memory_barrier *)0xffff0fa0)();
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_memory_barrier();
}
#endif
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
{
int32_t value = *ptr;
android_memory_barrier();
return value;
}
-extern ANDROID_ATOMIC_INLINE
-int32_t android_atomic_release_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
{
android_memory_barrier();
return *ptr;
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
{
*ptr = value;
android_memory_barrier();
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
{
android_memory_barrier();
*ptr = value;
@@ -101,8 +95,8 @@
extern int android_atomic_cas(int32_t old_value, int32_t new_value,
volatile int32_t *ptr);
#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
{
int32_t prev, status;
do {
@@ -117,8 +111,8 @@
return prev != old_value;
}
#else
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
{
typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *);
int32_t prev, status;
@@ -133,20 +127,18 @@
}
#endif
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
int status = android_atomic_cas(old_value, new_value, ptr);
android_memory_barrier();
return status;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
android_memory_barrier();
return android_atomic_cas(old_value, new_value, ptr);
@@ -157,8 +149,8 @@
extern int32_t android_atomic_add(int32_t increment,
volatile int32_t *ptr);
#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
{
int32_t prev, tmp, status;
android_memory_barrier();
@@ -174,8 +166,8 @@
return prev;
}
#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
@@ -187,12 +179,12 @@
}
#endif
-extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
{
return android_atomic_add(1, addr);
}
-extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
{
return android_atomic_add(-1, addr);
}
@@ -200,8 +192,7 @@
#if defined(__thumb__)
extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr);
#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
{
int32_t prev, tmp, status;
android_memory_barrier();
@@ -217,8 +208,7 @@
return prev;
}
#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
@@ -233,8 +223,7 @@
#if defined(__thumb__)
extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr);
#elif defined(__ARM_HAVE_LDREX_STREX)
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
{
int32_t prev, tmp, status;
android_memory_barrier();
@@ -250,8 +239,7 @@
return prev;
}
#else
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
index f9d3e25..49144a3 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -19,66 +19,60 @@
#include <stdint.h>
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+extern inline void android_compiler_barrier(void)
{
__asm__ __volatile__ ("" : : : "memory");
}
#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
android_compiler_barrier();
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_compiler_barrier();
}
#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
__asm__ __volatile__ ("sync" : : : "memory");
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
__asm__ __volatile__ ("sync" : : : "memory");
}
#endif
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_acquire_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
{
int32_t value = *ptr;
android_memory_barrier();
return value;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_release_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
{
android_memory_barrier();
return *ptr;
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
{
*ptr = value;
android_memory_barrier();
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
{
android_memory_barrier();
*ptr = value;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
{
int32_t prev, status;
do {
@@ -96,28 +90,26 @@
return prev != old_value;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
int status = android_atomic_cas(old_value, new_value, ptr);
android_memory_barrier();
return status;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
android_memory_barrier();
return android_atomic_cas(old_value, new_value, ptr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_swap(int32_t new_value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_swap(int32_t new_value,
+ volatile int32_t *ptr)
{
int32_t prev, status;
do {
@@ -133,8 +125,8 @@
return prev;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
@@ -150,20 +142,17 @@
return prev;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_inc(volatile int32_t *addr)
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
{
return android_atomic_add(1, addr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_dec(volatile int32_t *addr)
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
{
return android_atomic_add(-1, addr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
@@ -179,8 +168,7 @@
return prev;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
{
int32_t prev, status;
android_memory_barrier();
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
index 9480f57..438012e 100644
--- a/include/cutils/atomic-x86.h
+++ b/include/cutils/atomic-x86.h
@@ -19,66 +19,60 @@
#include <stdint.h>
-#ifndef ANDROID_ATOMIC_INLINE
-#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
-#endif
-
-extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+extern inline void android_compiler_barrier(void)
{
__asm__ __volatile__ ("" : : : "memory");
}
#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
android_compiler_barrier();
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_compiler_barrier();
}
#else
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+extern inline void android_memory_barrier(void)
{
__asm__ __volatile__ ("mfence" : : : "memory");
}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+extern inline void android_memory_store_barrier(void)
{
android_compiler_barrier();
}
#endif
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_acquire_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
{
int32_t value = *ptr;
android_compiler_barrier();
return value;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_release_load(volatile const int32_t *ptr)
+extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr)
{
android_memory_barrier();
return *ptr;
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_acquire_store(int32_t value,
+ volatile int32_t *ptr)
{
*ptr = value;
android_memory_barrier();
}
-extern ANDROID_ATOMIC_INLINE void
-android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+extern inline void android_atomic_release_store(int32_t value,
+ volatile int32_t *ptr)
{
android_compiler_barrier();
*ptr = value;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+extern inline int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
{
int32_t prev;
__asm__ __volatile__ ("lock; cmpxchgl %1, %2"
@@ -88,26 +82,24 @@
return prev != old_value;
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_acquire_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
/* Loads are not reordered with other loads. */
return android_atomic_cas(old_value, new_value, ptr);
}
-extern ANDROID_ATOMIC_INLINE int
-android_atomic_release_cas(int32_t old_value,
- int32_t new_value,
- volatile int32_t *ptr)
+extern inline int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
{
/* Stores are not reordered with other stores. */
return android_atomic_cas(old_value, new_value, ptr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_add(int32_t increment, volatile int32_t *ptr)
+extern inline int32_t android_atomic_add(int32_t increment,
+ volatile int32_t *ptr)
{
__asm__ __volatile__ ("lock; xaddl %0, %1"
: "+r" (increment), "+m" (*ptr)
@@ -116,20 +108,18 @@
return increment;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_inc(volatile int32_t *addr)
+extern inline int32_t android_atomic_inc(volatile int32_t *addr)
{
return android_atomic_add(1, addr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_dec(volatile int32_t *addr)
+extern inline int32_t android_atomic_dec(volatile int32_t *addr)
{
return android_atomic_add(-1, addr);
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_and(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_and(int32_t value,
+ volatile int32_t *ptr)
{
int32_t prev, status;
do {
@@ -139,8 +129,7 @@
return prev;
}
-extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_or(int32_t value, volatile int32_t *ptr)
+extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
{
int32_t prev, status;
do {
diff --git a/include/cutils/log.h b/include/cutils/log.h
index 8b045c7..878952e 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -279,88 +279,7 @@
: (void)0 )
#endif
-// ---------------------------------------------------------------------
-
-/*
- * Simplified macro to send a verbose radio log message using the current LOG_TAG.
- */
-#ifndef RLOGV
-#if LOG_NDEBUG
-#define RLOGV(...) ((void)0)
-#else
-#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#endif
-#endif
-
-#define CONDITION(cond) (__builtin_expect((cond)!=0, 0))
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...) ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
- ( (CONDITION(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using the current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
- ( (CONDITION(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an info radio log message using the current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
- ( (CONDITION(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using the current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
- ( (CONDITION(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
-/*
- * Simplified macro to send an error radio log message using the current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
- ( (CONDITION(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : (void)0 )
-#endif
-
+
// ---------------------------------------------------------------------
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/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 746bec3..1159a15 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -62,7 +62,6 @@
#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_LOOP_RADIO 1030 /* loop radio devices */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -142,7 +141,6 @@
{ "loop_radio", AID_LOOP_RADIO, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
- { "clat", AID_CLAT, },
};
#define android_id_count \
@@ -238,10 +236,6 @@
struct fs_path_config *pc;
int plen;
- if (path[0] == '/') {
- path++;
- }
-
pc = dir ? android_dirs : android_files;
plen = strlen(path);
for(; pc->prefix; pc++){
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index f1a4b43..756bacf 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -23,11 +23,10 @@
class FrameworkListener : public SocketListener {
public:
- static const int CMD_ARGS_MAX = 26;
+ static const int CMD_ARGS_MAX = 16;
/* 1 out of errorRate will be dropped */
int errorRate;
-
private:
int mCommandCount;
bool mWithSeq;
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 1d67c12..9a6b59c 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -72,19 +72,6 @@
/* Call this to cleanup the USB host library. */
void usb_host_cleanup(struct usb_host_context *context);
-/* Call this to get the inotify file descriptor. */
-int usb_host_get_fd(struct usb_host_context *context);
-
-/* Call this to initialize the usb host context. */
-int usb_host_load(struct usb_host_context *context,
- usb_device_added_cb added_cb,
- usb_device_removed_cb removed_cb,
- usb_discovery_done_cb discovery_done_cb,
- void *client_data);
-
-/* Call this to read and handle occuring usb event. */
-int usb_host_read_event(struct usb_host_context *context);
-
/* Call this to monitor the USB bus for new and removed devices.
* This is intended to be called from a dedicated thread,
* as it will not return until one of the callbacks returns true.
diff --git a/init/Android.mk b/init/Android.mk
index 00d2144..a1c1e7a 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -33,11 +33,13 @@
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := \
- libfs_mgr \
- libcutils \
- libc \
- libselinux
+LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc
+
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
include $(BUILD_EXECUTABLE)
diff --git a/init/builtins.c b/init/builtins.c
index dc7900e..aaf85d9 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,8 +35,10 @@
#include <sys/system_properties.h>
#include <fs_mgr.h>
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
+#endif
#include "init.h"
#include "keywords.h"
@@ -513,20 +515,24 @@
}
int do_setcon(int nargs, char **args) {
+#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 0;
if (setcon(args[1]) < 0) {
return -errno;
}
+#endif
return 0;
}
int do_setenforce(int nargs, char **args) {
+#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 0;
if (security_setenforce(atoi(args[1])) < 0) {
return -errno;
}
+#endif
return 0;
}
@@ -754,30 +760,36 @@
}
int do_setsebool(int nargs, char **args) {
- const char *name = args[1];
- const char *value = args[2];
- SELboolean b;
- int ret;
+#ifdef HAVE_SELINUX
+ SELboolean *b = alloca(nargs * sizeof(SELboolean));
+ char *v;
+ int i;
if (is_selinux_enabled() <= 0)
return 0;
- b.name = name;
- if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
- b.value = 1;
- else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
- b.value = 0;
- else {
- ERROR("setsebool: invalid value %s\n", value);
- return -EINVAL;
+ for (i = 1; i < nargs; i++) {
+ char *name = args[i];
+ v = strchr(name, '=');
+ if (!v) {
+ ERROR("setsebool: argument %s had no =\n", name);
+ return -EINVAL;
+ }
+ *v++ = 0;
+ b[i-1].name = name;
+ if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
+ b[i-1].value = 1;
+ else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
+ b[i-1].value = 0;
+ else {
+ ERROR("setsebool: invalid value %s\n", v);
+ return -EINVAL;
+ }
}
- if (security_set_boolean_list(1, &b, 0) < 0) {
- ret = -errno;
- ERROR("setsebool: could not set %s to %s\n", name, value);
- return ret;
- }
-
+ if (security_set_boolean_list(nargs - 1, b, 0) < 0)
+ return -errno;
+#endif
return 0;
}
diff --git a/init/devices.c b/init/devices.c
index b07a1a6..c30303f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -30,9 +30,11 @@
#include <sys/un.h>
#include <linux/netlink.h>
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
+#endif
#include <private/android_filesystem_config.h>
#include <sys/time.h>
@@ -51,7 +53,9 @@
#define FIRMWARE_DIR2 "/vendor/firmware"
#define FIRMWARE_DIR3 "/firmware/image"
+#ifdef HAVE_SELINUX
extern struct selabel_handle *sehandle;
+#endif
static int device_fd = -1;
@@ -189,15 +193,17 @@
unsigned gid;
mode_t mode;
dev_t dev;
+#ifdef HAVE_SELINUX
char *secontext = NULL;
+#endif
mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
-
+#ifdef HAVE_SELINUX
if (sehandle) {
selabel_lookup(sehandle, &secontext, path, mode);
setfscreatecon(secontext);
}
-
+#endif
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
@@ -208,11 +214,12 @@
mknod(path, mode, dev);
chown(path, uid, -1);
setegid(AID_ROOT);
-
+#ifdef HAVE_SELINUX
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
+#endif
}
static void add_platform_device(const char *name)
@@ -875,14 +882,14 @@
suseconds_t t0, t1;
struct stat info;
int fd;
-
+#ifdef HAVE_SELINUX
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
}
-
- /* is 256K enough? udev uses 16MB! */
- device_fd = uevent_open_socket(256*1024, true);
+#endif
+ /* is 64K enough? udev uses 16MB! */
+ device_fd = uevent_open_socket(64*1024, true);
if(device_fd < 0)
return;
diff --git a/init/init.c b/init/init.c
index 48d8559..fa2b4e8 100755
--- a/init/init.c
+++ b/init/init.c
@@ -33,9 +33,11 @@
#include <sys/un.h>
#include <sys/personality.h>
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
+#endif
#include <libgen.h>
@@ -59,8 +61,10 @@
#include "ueventd.h"
#include "watchdogd.h"
+#ifdef HAVE_SELINUX
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
+#endif
static int property_triggers_enabled = 0;
@@ -74,7 +78,9 @@
static unsigned revision = 0;
static char qemu[32];
+#ifdef HAVE_SELINUX
static int selinux_enabled = 1;
+#endif
static struct action *cur_action = NULL;
static struct command *cur_command = NULL;
@@ -158,9 +164,10 @@
pid_t pid;
int needs_console;
int n;
+#ifdef HAVE_SELINUX
char *scon = NULL;
int rc;
-
+#endif
/* starting a service removes it from the disabled or reset
* state and immediately takes it out of the restarting
* state if it was in there
@@ -197,6 +204,7 @@
return;
}
+#ifdef HAVE_SELINUX
if (is_selinux_enabled() > 0) {
if (svc->seclabel) {
scon = strdup(svc->seclabel);
@@ -230,6 +238,7 @@
}
}
}
+#endif
NOTICE("starting '%s'\n", svc->name);
@@ -266,7 +275,9 @@
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
+#ifdef HAVE_SELINUX
setsockcreatecon(scon);
+#endif
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
@@ -279,9 +290,11 @@
}
}
+#ifdef HAVE_SELINUX
freecon(scon);
scon = NULL;
setsockcreatecon(NULL);
+#endif
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
@@ -327,12 +340,15 @@
_exit(127);
}
}
+
+#ifdef HAVE_SELINUX
if (svc->seclabel) {
if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
_exit(127);
}
}
+#endif
if (!dynamic_args) {
if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
@@ -359,7 +375,9 @@
_exit(127);
}
+#ifdef HAVE_SELINUX
freecon(scon);
+#endif
if (pid < 0) {
ERROR("failed to start '%s'\n", svc->name);
@@ -610,9 +628,11 @@
*value++ = 0;
if (name_len == 0) return;
+#ifdef HAVE_SELINUX
if (!strcmp(name,"selinux")) {
selinux_enabled = atoi(value);
}
+#endif
if (for_emulator) {
/* in the emulator, export any kernel option with the
@@ -760,6 +780,7 @@
}
#endif
+#ifdef HAVE_SELINUX
static const struct selinux_opt seopts_prop[] = {
{ SELABEL_OPT_PATH, "/data/system/property_contexts" },
{ SELABEL_OPT_PATH, "/property_contexts" },
@@ -818,6 +839,8 @@
return 0;
}
+#endif
+
int main(int argc, char **argv)
{
int fd_count = 0;
@@ -871,6 +894,7 @@
process_kernel_cmdline();
+#ifdef HAVE_SELINUX
union selinux_callback cb;
cb.func_log = klog_write;
selinux_set_callback(SELINUX_CB_LOG, cb);
@@ -895,6 +919,7 @@
*/
restorecon("/dev");
restorecon("/dev/socket");
+#endif
is_charger = !strcmp(bootmode, "charger");
diff --git a/init/init.h b/init/init.h
index 955e1f0..b7e06c9 100644
--- a/init/init.h
+++ b/init/init.h
@@ -95,7 +95,9 @@
gid_t supp_gids[NR_SVC_SUPP_GIDS];
size_t nr_supp_gids;
+#ifdef HAVE_SELINUX
char *seclabel;
+#endif
struct socketinfo *sockets;
struct svcenvinfo *envvars;
@@ -134,8 +136,10 @@
int load_565rle_image( char *file_name );
+#ifdef HAVE_SELINUX
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
extern int selinux_reload_policy(void);
+#endif
#endif /* _INIT_INIT_H */
diff --git a/init/init_parser.c b/init/init_parser.c
index beb9188..5393e52 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -799,11 +799,13 @@
}
break;
case K_seclabel:
+#ifdef HAVE_SELINUX
if (nargs != 2) {
parse_error(state, "seclabel option requires a label string\n");
} else {
svc->seclabel = args[1];
}
+#endif
break;
default:
diff --git a/init/keywords.h b/init/keywords.h
index f188db5..97d4950 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -78,7 +78,7 @@
KEYWORD(setkey, COMMAND, 0, do_setkey)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
- KEYWORD(setsebool, COMMAND, 2, do_setsebool)
+ KEYWORD(setsebool, COMMAND, 1, do_setsebool)
KEYWORD(socket, OPTION, 0, 0)
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
diff --git a/init/property_service.c b/init/property_service.c
index 61dd86f..f58e07d 100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -40,8 +40,10 @@
#include <sys/atomics.h>
#include <private/android_filesystem_config.h>
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
+#endif
#include "property_service.h"
#include "init.h"
@@ -123,7 +125,7 @@
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
- fd = open("/dev/__properties__", O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
+ fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);
if (fd < 0)
return -1;
@@ -136,7 +138,7 @@
close(fd);
- fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW);
+ fd = open("/dev/__properties__", O_RDONLY);
if (fd < 0)
return -1;
@@ -199,6 +201,7 @@
static int check_mac_perms(const char *name, char *sctx)
{
+#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 1;
@@ -222,10 +225,15 @@
freecon(tctx);
err:
return result;
+
+#endif
+ return 1;
}
static int check_control_mac_perms(const char *name, char *sctx)
{
+#ifdef HAVE_SELINUX
+
/*
* Create a name prefix out of ctl.<service name>
* The new prefix allows the use of the existing
@@ -239,6 +247,9 @@
return 0;
return check_mac_perms(ctl_name, sctx);
+
+#endif
+ return 1;
}
/*
@@ -309,12 +320,13 @@
static void write_persistent_property(const char *name, const char *value)
{
- char tempPath[PATH_MAX];
+ const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp";
char path[PATH_MAX];
- int fd;
+ int fd, length;
- snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
- fd = mkstemp(tempPath);
+ snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
+
+ fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
if (fd < 0) {
ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
return;
@@ -322,7 +334,6 @@
write(fd, value, strlen(value));
close(fd);
- snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
if (rename(tempPath, path)) {
unlink(tempPath);
ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
@@ -334,8 +345,8 @@
prop_area *pa;
prop_info *pi;
- size_t namelen = strlen(name);
- size_t valuelen = strlen(value);
+ int namelen = strlen(name);
+ int valuelen = strlen(value);
if(namelen >= PROP_NAME_MAX) return -1;
if(valuelen >= PROP_VALUE_MAX) return -1;
@@ -385,9 +396,11 @@
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value);
+#ifdef HAVE_SELINUX
} else if (strcmp("selinux.reload_policy", name) == 0 &&
strcmp("1", value) == 0) {
selinux_reload_policy();
+#endif
}
property_changed(name, value);
return 0;
@@ -412,13 +425,13 @@
/* Check socket options here */
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
- ERROR("Unable to receive socket options\n");
+ ERROR("Unable to recieve socket options\n");
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
+ ERROR("sys_prop: mis-match msg size recieved: %d expected: %d errno: %d\n",
r, sizeof(prop_msg), errno);
close(s);
return;
@@ -429,7 +442,9 @@
msg.name[PROP_NAME_MAX-1] = 0;
msg.value[PROP_VALUE_MAX-1] = 0;
+#ifdef HAVE_SELINUX
getpeercon(s, &source_ctx);
+#endif
if(memcmp(msg.name,"ctl.",4) == 0) {
// Keep the old close-socket-early behavior when handling
@@ -454,7 +469,10 @@
// the property is written to memory.
close(s);
}
+#ifdef HAVE_SELINUX
freecon(source_ctx);
+#endif
+
break;
default:
@@ -512,14 +530,12 @@
static void load_persistent_properties()
{
DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
- int dir_fd;
struct dirent* entry;
+ char path[PATH_MAX];
char value[PROP_VALUE_MAX];
int fd, length;
- struct stat sb;
if (dir) {
- dir_fd = dirfd(dir);
while ((entry = readdir(dir)) != NULL) {
if (strncmp("persist.", entry->d_name, strlen("persist.")))
continue;
@@ -528,39 +544,20 @@
continue;
#endif
/* open the file and read the property value */
- fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
- if (fd < 0) {
- ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
- entry->d_name, errno);
- continue;
- }
- if (fstat(fd, &sb) < 0) {
- ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
+ snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, entry->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ length = read(fd, value, sizeof(value) - 1);
+ if (length >= 0) {
+ value[length] = 0;
+ property_set(entry->d_name, value);
+ } else {
+ ERROR("Unable to read persistent property file %s errno: %d\n", path, errno);
+ }
close(fd);
- continue;
- }
-
- // File must not be accessible to others, be owned by root/root, and
- // not be a hard link to any other file.
- if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0)
- || (sb.st_uid != 0)
- || (sb.st_gid != 0)
- || (sb.st_nlink != 1)) {
- ERROR("skipping insecure property file %s (uid=%lu gid=%lu nlink=%d mode=%o)\n",
- entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
- close(fd);
- continue;
- }
-
- length = read(fd, value, sizeof(value) - 1);
- if (length >= 0) {
- value[length] = 0;
- property_set(entry->d_name, value);
} else {
- ERROR("Unable to read persistent property file %s errno: %d\n",
- entry->d_name, errno);
+ ERROR("Unable to open persistent property file %s errno: %d\n", path, errno);
}
- close(fd);
}
closedir(dir);
} else {
diff --git a/init/readme.txt b/init/readme.txt
index 7a5997d..fe0d15d 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -88,13 +88,6 @@
supplemental groups of the process (via setgroups()).
Currently defaults to root. (??? probably should default to nobody)
-seclabel <securitycontext>
- Change to securitycontext before exec'ing this service.
- Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
- Services on the system partition can instead use policy-defined transitions
- based on their file security context.
- If not specified and no transition is defined in policy, defaults to the init context.
-
oneshot
Do not restart the service when it exits.
@@ -189,21 +182,6 @@
device by name.
<mountoption>s include "ro", "rw", "remount", "noatime", ...
-restorecon <path>
- Restore the file named by <path> to the security context specified
- in the file_contexts configuration.
- Not required for directories created by the init.rc as these are
- automatically labeled correctly by init.
-
-setcon <securitycontext>
- Set the current process security context to the specified string.
- This is typically only used from early-init to set the init context
- before any other process is started.
-
-setenforce 0|1
- Set the SELinux system-wide enforcing status.
- 0 is permissive (i.e. log but do not deny), 1 is enforcing.
-
setkey
TBD
@@ -213,10 +191,6 @@
setrlimit <resource> <cur> <max>
Set the rlimit for a resource.
-setsebool <name> <value>
- Set SELinux boolean <name> to <value>.
- <value> may be 1|true|on or 0|false|off
-
start <service>
Start a service running if it is not already running.
diff --git a/init/util.c b/init/util.c
index 918bc05..743748b 100755
--- a/init/util.c
+++ b/init/util.c
@@ -23,7 +23,9 @@
#include <errno.h>
#include <time.h>
+#ifdef HAVE_SELINUX
#include <selinux/label.h>
+#endif
#include <sys/stat.h>
#include <sys/types.h>
@@ -87,7 +89,9 @@
{
struct sockaddr_un addr;
int fd, ret;
+#ifdef HAVE_SELINUX
char *secon;
+#endif
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
@@ -106,12 +110,14 @@
goto out_close;
}
+#ifdef HAVE_SELINUX
secon = NULL;
if (sehandle) {
ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
if (ret == 0)
setfscreatecon(secon);
}
+#endif
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
if (ret) {
@@ -119,8 +125,10 @@
goto out_unlink;
}
+#ifdef HAVE_SELINUX
setfscreatecon(NULL);
freecon(secon);
+#endif
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
@@ -460,27 +468,31 @@
{
int rc;
+#ifdef HAVE_SELINUX
char *secontext = NULL;
if (sehandle) {
selabel_lookup(sehandle, &secontext, path, mode);
setfscreatecon(secontext);
}
+#endif
rc = mkdir(path, mode);
+#ifdef HAVE_SELINUX
if (secontext) {
int save_errno = errno;
freecon(secontext);
setfscreatecon(NULL);
errno = save_errno;
}
-
+#endif
return rc;
}
int restorecon(const char *pathname)
{
+#ifdef HAVE_SELINUX
char *secontext = NULL;
struct stat sb;
int i;
@@ -497,5 +509,6 @@
return -errno;
}
freecon(secontext);
+#endif
return 0;
}
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index 03dbd53..3697d18 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -35,8 +35,10 @@
#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__)
@@ -254,6 +256,7 @@
if (mi->name[0]) {
symbol->map_name = strdup(mi->name);
}
+#if HAVE_DLADDR
Dl_info info;
if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
@@ -261,6 +264,7 @@
symbol->symbol_name = strdup(info.dli_sname);
symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
}
+#endif
}
}
release_my_map_info_list(milist);
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
index 6a27664..3c52854 100644
--- a/libcorkscrew/map_info.c
+++ b/libcorkscrew/map_info.c
@@ -57,15 +57,13 @@
mi->start = start;
mi->end = end;
mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
- mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
mi->data = NULL;
memcpy(mi->name, name, name_len);
mi->name[name_len] = '\0';
ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+ "is_readable=%d, is_executable=%d, name=%s",
+ mi->start, mi->end, mi->is_readable, mi->is_executable, mi->name);
}
return mi;
}
@@ -112,11 +110,6 @@
return mi && mi->is_readable;
}
-bool is_writable_map(const map_info_t* milist, uintptr_t addr) {
- const map_info_t* mi = find_map_info(milist, addr);
- return mi && mi->is_writable;
-}
-
bool is_executable_map(const map_info_t* milist, uintptr_t addr) {
const map_info_t* mi = find_map_info(milist, addr);
return mi && mi->is_executable;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index fc6d08d..d9bd8d8 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -77,8 +77,12 @@
abort_socket.c \
fs.c \
selector.c \
+ tztime.c \
multiuser.c \
zygote.c
+
+ commonHostSources += \
+ tzstrftime.c
endif
diff --git a/libcutils/atomic.c b/libcutils/atomic.c
index 1484ef8..f6cd8b0 100644
--- a/libcutils/atomic.c
+++ b/libcutils/atomic.c
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-#define ANDROID_ATOMIC_INLINE
+#define inline
#include <cutils/atomic-inline.h>
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/liblog/logd_write.c b/liblog/logd_write.c
index d812abc..b91de52 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -134,7 +134,6 @@
{
struct iovec vec[3];
log_id_t log_id = LOG_ID_MAIN;
- char tmp_tag[32];
if (!tag)
tag = "";
@@ -148,12 +147,8 @@
!strcmp(tag, "STK") ||
!strcmp(tag, "CDMA") ||
!strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS")) {
+ !strcmp(tag, "SMS"))
log_id = LOG_ID_RADIO;
- // Inform third party apps/ril/radio.. to use Rlog or RLOG
- snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
- tag = tmp_tag;
- }
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
@@ -168,14 +163,12 @@
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
{
struct iovec vec[3];
- char tmp_tag[32];
if (!tag)
tag = "";
/* XXX: This needs to go! */
- if ((bufID != LOG_ID_RADIO) &&
- (!strcmp(tag, "HTC_RIL") ||
+ 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") ||
@@ -183,12 +176,8 @@
!strcmp(tag, "STK") ||
!strcmp(tag, "CDMA") ||
!strcmp(tag, "PHONE") ||
- !strcmp(tag, "SMS"))) {
+ !strcmp(tag, "SMS"))
bufID = LOG_ID_RADIO;
- // Inform third party apps/ril/radio.. to use Rlog or RLOG
- snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
- tag = tmp_tag;
- }
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index b4caaf9..d0ca90a 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -211,7 +211,7 @@
p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
else
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
- p2p_interface, DHCP_CONFIG_PATH, interface);
+ 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/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index eb1f66e..7d1d973 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -33,6 +33,8 @@
return 0;
}
+ autosuspend_inited = true;
+
autosuspend_ops = autosuspend_earlysuspend_init();
if (autosuspend_ops) {
goto out;
@@ -54,8 +56,6 @@
}
out:
- autosuspend_inited = true;
-
ALOGV("autosuspend initialized\n");
return 0;
}
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 02a401d..6731cf1 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -25,8 +25,6 @@
#include <sysutils/FrameworkCommand.h>
#include <sysutils/SocketClient.h>
-static const int CMD_BUF_SIZE = 1024;
-
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
init(socketName, withSeq);
@@ -45,7 +43,7 @@
}
bool FrameworkListener::onDataAvailable(SocketClient *c) {
- char buffer[CMD_BUF_SIZE];
+ char buffer[255];
int len;
len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
@@ -54,8 +52,6 @@
return false;
} else if (!len)
return false;
- if(buffer[len-1] != '\0')
- SLOGW("String is not zero-terminated");
int offset = 0;
int i;
@@ -67,7 +63,6 @@
offset = i + 1;
}
}
-
return true;
}
@@ -79,7 +74,7 @@
FrameworkCommandCollection::iterator i;
int argc = 0;
char *argv[FrameworkListener::CMD_ARGS_MAX];
- char tmp[CMD_BUF_SIZE];
+ char tmp[255];
char *p = data;
char *q = tmp;
char *qlimit = tmp + sizeof(tmp) - 1;
@@ -185,6 +180,7 @@
goto out;
}
}
+
cli->sendMsg(500, "Command not recognized", false);
out:
int j;
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 9565cc5..52b4ead 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -44,13 +44,3 @@
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_SHARED_LIBRARY)
-
-# Static library for target
-# ========================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libusbhost
-LOCAL_SRC_FILES := usbhost.c
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 167fa60..c059b89 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -33,7 +33,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <stddef.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -51,23 +50,16 @@
#include "usbhost/usbhost.h"
#define DEV_DIR "/dev"
-#define USB_FS_DIR DEV_DIR "/bus/usb"
-#define USB_FS_ID_SCANNER USB_FS_DIR "/%d/%d"
-#define USB_FS_ID_FORMAT USB_FS_DIR "/%03d/%03d"
+#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"
// From drivers/usb/core/devio.c
// I don't know why this isn't in a kernel header
#define MAX_USBFS_BUFFER_SIZE 16384
-#define MAX_USBFS_WD_COUNT 10
-
struct usb_host_context {
- int fd;
- usb_device_added_cb cb_added;
- usb_device_removed_cb cb_removed;
- void *data;
- int wds[MAX_USBFS_WD_COUNT];
- int wdd;
+ int fd;
};
struct usb_device {
@@ -124,10 +116,10 @@
while ((de = readdir(busdir)) != 0 && !done) {
if(badname(de->d_name)) continue;
- snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name);
+ snprintf(busname, sizeof(busname), "%s/%s", USB_FS_DIR, de->d_name);
done = find_existing_devices_bus(busname, added_cb,
client_data);
- } //end of busdir while
+ }
closedir(busdir);
return done;
@@ -145,7 +137,7 @@
/* watch existing subdirectories of USB_FS_DIR */
for (i = 1; i < wd_count; i++) {
- snprintf(path, sizeof(path), USB_FS_DIR "/%03d", 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;
@@ -174,126 +166,93 @@
free(context);
}
-int usb_host_get_fd(struct usb_host_context *context)
-{
- return context->fd;
-} /* usb_host_get_fd() */
-
-int usb_host_load(struct usb_host_context *context,
- usb_device_added_cb added_cb,
- usb_device_removed_cb removed_cb,
- usb_discovery_done_cb discovery_done_cb,
- void *client_data)
-{
- int done = 0;
- int i;
-
- context->cb_added = added_cb;
- context->cb_removed = removed_cb;
- context->data = client_data;
-
- D("Created device discovery thread\n");
-
- /* watch for files added and deleted within USB_FS_DIR */
- for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
- context->wds[i] = -1;
-
- /* watch the root for new subdirectories */
- context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
- if (context->wdd < 0) {
- fprintf(stderr, "inotify_add_watch failed\n");
- if (discovery_done_cb)
- discovery_done_cb(client_data);
- return done;
- }
-
- watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
-
- /* check for existing devices first, after we have inotify set up */
- done = find_existing_devices(added_cb, client_data);
- if (discovery_done_cb)
- done |= discovery_done_cb(client_data);
-
- return done;
-} /* usb_host_load() */
-
-int usb_host_read_event(struct usb_host_context *context)
-{
- struct inotify_event* event;
- char event_buf[512];
- char path[100];
- int i, ret, done = 0;
- int j, event_size;
- int wd;
-
- ret = read(context->fd, event_buf, sizeof(event_buf));
- if (ret >= (int)sizeof(struct inotify_event)) {
- event = (struct inotify_event *)event_buf;
- wd = event->wd;
- if (wd == context->wdd) {
- if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
- watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
- done = find_existing_devices(context->cb_added, context->data);
- } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
- for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
- if (context->wds[i] >= 0) {
- inotify_rm_watch(context->fd, context->wds[i]);
- context->wds[i] = -1;
- }
- }
- }
- } else if (wd == context->wds[0]) {
- i = atoi(event->name);
- snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
- D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
- "new" : "gone", path, i);
- if (i > 0 && i < MAX_USBFS_WD_COUNT) {
- if (event->mask & IN_CREATE) {
- ret = inotify_add_watch(context->fd, path,
- IN_CREATE | IN_DELETE);
- if (ret >= 0)
- context->wds[i] = ret;
- done = find_existing_devices_bus(path, context->cb_added,
- context->data);
- } else if (event->mask & IN_DELETE) {
- inotify_rm_watch(context->fd, context->wds[i]);
- context->wds[i] = -1;
- }
- }
- } else {
- for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
- if (wd == context->wds[i]) {
- snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
- if (event->mask == IN_CREATE) {
- D("new device %s\n", path);
- done = context->cb_added(path, context->data);
- } else if (event->mask == IN_DELETE) {
- D("gone device %s\n", path);
- done = context->cb_removed(path, context->data);
- }
- }
- }
- }
- }
-
- return done;
-} /* usb_host_read_event() */
-
void usb_host_run(struct usb_host_context *context,
usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb,
void *client_data)
{
- int done;
+ struct inotify_event* event;
+ char event_buf[512];
+ char path[100];
+ int i, ret, done = 0;
+ int wd, wdd, wds[10];
+ int wd_count = sizeof(wds) / sizeof(wds[0]);
- done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);
+ D("Created device discovery thread\n");
+
+ /* watch for files added and deleted within USB_FS_DIR */
+ for (i = 0; i < wd_count; i++)
+ wds[i] = -1;
+
+ /* watch the root for new subdirectories */
+ 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_subdirs(context, wds, wd_count);
+
+ /* check for existing devices first, after we have inotify set up */
+ done = find_existing_devices(added_cb, client_data);
+ if (discovery_done_cb)
+ done |= discovery_done_cb(client_data);
while (!done) {
-
- done = usb_host_read_event(context);
+ ret = read(context->fd, event_buf, sizeof(event_buf));
+ if (ret >= (int)sizeof(struct inotify_event)) {
+ event = (struct inotify_event *)event_buf;
+ wd = event->wd;
+ 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("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
+ "new" : "gone", path, i);
+ if (i > 0 && i < wd_count) {
+ 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++) {
+ if (wd == wds[i]) {
+ snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
+ if (event->mask == IN_CREATE) {
+ D("new device %s\n", path);
+ done = added_cb(path, client_data);
+ } else if (event->mask == IN_DELETE) {
+ D("gone device %s\n", path);
+ done = removed_cb(path, client_data);
+ }
+ }
+ }
+ }
+ }
}
-} /* usb_host_run() */
+}
struct usb_device *usb_device_open(const char *dev_name)
{
@@ -647,6 +606,7 @@
{
struct usbdevfs_urb *urb = NULL;
struct usb_request *req = NULL;
+ int res;
while (1) {
int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 6040bd9..09640e1 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -150,8 +150,5 @@
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/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index a0c1c4f..cde9dee 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -5,7 +5,7 @@
symlink /mnt/sdcard /sdcard
on boot
- setsebool in_qemu 1
+ setsebool in_qemu=1
restorecon /sys/qemu_trace/process_name
restorecon /sys/qemu_trace/state
restorecon /sys/qemu_trace/symbol
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 871a1f7..0face12 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -120,12 +120,6 @@
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
-# qtaguid will limit access to specific data based on group memberships.
-# net_bw_acct grants impersonation of socket owners.
-# net_bw_stats grants access to other apps' detailed tagged-socket stats.
- chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
- chown root net_bw_stats /proc/net/xt_qtaguid/stats
-
# Allow everybody to read the xt_qtaguid resource tracking misc dev.
# This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
@@ -206,7 +200,6 @@
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
# give system access to wpa_supplicant.conf for backup and restore
@@ -503,6 +496,7 @@
class main
user keystore
group keystore drmrpc
+ socket keystore stream 666
service dumpstate /system/bin/dumpstate -s
class main
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index dbbce06..086ba0d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -57,7 +57,11 @@
touch \
lsof \
du \
- md5 \
+ md5
+
+ifeq ($(HAVE_SELINUX),true)
+
+TOOLS += \
getenforce \
setenforce \
chcon \
@@ -67,6 +71,9 @@
setsebool \
load_policy
+endif
+
+
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
TOOLS += r
endif
@@ -83,13 +90,17 @@
cp/cp.c cp/utils.c \
grep/grep.c grep/fastgrep.c grep/file.c grep/queue.c grep/util.c
+LOCAL_SHARED_LIBRARIES := libcutils libc libusbhost
+
LOCAL_C_INCLUDES := bionic/libc/bionic
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libc \
- libusbhost \
- libselinux
+ifeq ($(HAVE_SELINUX),true)
+
+LOCAL_CFLAGS += -DHAVE_SELINUX
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_C_INCLUDES += external/libselinux/include
+
+endif
LOCAL_MODULE := toolbox
diff --git a/toolbox/df.c b/toolbox/df.c
index 9cd0743..63940a1 100644
--- a/toolbox/df.c
+++ b/toolbox/df.c
@@ -9,22 +9,16 @@
static void printsize(long long n)
{
char unit = 'K';
- long long t;
-
- n *= 10;
-
- if (n > 1024*1024*10) {
+ n /= 1024;
+ if (n > 1024) {
n /= 1024;
unit = 'M';
}
-
- if (n > 1024*1024*10) {
+ if (n > 1024) {
n /= 1024;
unit = 'G';
}
-
- t = (n + 512) / 1024;
- printf("%4lld.%1lld%c", t/10, t%10, unit);
+ printf("%4lld%c", n, unit);
}
static void df(char *s, int always) {
@@ -47,7 +41,7 @@
}
int df_main(int argc, char *argv[]) {
- printf("Filesystem Size Used Free Blksize\n");
+ printf("Filesystem Size Used Free Blksize\n");
if (argc == 1) {
char s[2000];
FILE *f = fopen("/proc/mounts", "r");
diff --git a/toolbox/id.c b/toolbox/id.c
index 8ec79c1..bc79288 100644
--- a/toolbox/id.c
+++ b/toolbox/id.c
@@ -4,7 +4,10 @@
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
+
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
+#endif
static void print_uid(uid_t uid)
{
@@ -31,7 +34,9 @@
{
gid_t list[64];
int n, max;
+#ifdef HAVE_SELINUX
char *secctx;
+#endif
max = getgroups(64, list);
if (max < 0) max = 0;
@@ -48,10 +53,12 @@
print_gid(list[n]);
}
}
+#ifdef HAVE_SELINUX
if (getcon(&secctx) == 0) {
printf(" context=%s", secctx);
free(secctx);
}
+#endif
printf("\n");
return 0;
}
diff --git a/toolbox/ls.c b/toolbox/ls.c
index e530521..a4db99c 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -5,7 +5,9 @@
#include <dirent.h>
#include <errno.h>
+#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
+#endif
#include <sys/stat.h>
#include <unistd.h>
@@ -258,7 +260,11 @@
return -1;
}
+#ifdef HAVE_SELINUX
lgetfilecon(path, &maclabel);
+#else
+ maclabel = strdup("-");
+#endif
if (!maclabel) {
return -1;
}
@@ -270,12 +276,12 @@
switch(s.st_mode & S_IFMT) {
case S_IFLNK: {
char linkto[256];
- ssize_t len;
+ int len;
len = readlink(path, linkto, sizeof(linkto));
if(len < 0) return -1;
- if((size_t)len > sizeof(linkto)-1) {
+ if(len > sizeof(linkto)-1) {
linkto[sizeof(linkto)-4] = '.';
linkto[sizeof(linkto)-3] = '.';
linkto[sizeof(linkto)-2] = '.';
@@ -301,7 +307,7 @@
static int listfile(const char *dirname, const char *filename, int flags)
{
- if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL)) == 0) {
+ if ((flags & LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL) == 0) {
printf("%s\n", filename);
return 0;
}
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
index f79a612..4a3d87d 100644
--- a/toolbox/setsebool.c
+++ b/toolbox/setsebool.c
@@ -9,26 +9,35 @@
#include <errno.h>
static int do_setsebool(int nargs, char **args) {
- const char *name = args[1];
- const char *value = args[2];
- SELboolean b;
+ SELboolean *b = alloca(nargs * sizeof(SELboolean));
+ char *v;
+ int i;
if (is_selinux_enabled() <= 0)
return 0;
- b.name = name;
- if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
- b.value = 1;
- else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
- b.value = 0;
- else {
- fprintf(stderr, "setsebool: invalid value %s\n", value);
- return -1;
+ for (i = 1; i < nargs; i++) {
+ char *name = args[i];
+ v = strchr(name, '=');
+ if (!v) {
+ fprintf(stderr, "setsebool: argument %s had no =\n", name);
+ return -1;
+ }
+ *v++ = 0;
+ b[i-1].name = name;
+ if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
+ b[i-1].value = 1;
+ else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
+ b[i-1].value = 0;
+ else {
+ fprintf(stderr, "setsebool: invalid value %s\n", v);
+ return -1;
+ }
}
- if (security_set_boolean_list(1, &b, 0) < 0)
+ if (security_set_boolean_list(nargs - 1, b, 0) < 0)
{
- fprintf(stderr, "setsebool: could not set %s to %s: %s", name, value, strerror(errno));
+ fprintf(stderr, "setsebool: unable to set booleans: %s", strerror(errno));
return -1;
}
@@ -37,8 +46,8 @@
int setsebool_main(int argc, char **argv)
{
- if (argc != 3) {
- fprintf(stderr, "Usage: %s name value\n", argv[0]);
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s name=value...\n", argv[0]);
exit(1);
}