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 b5d93f8..07bfbe5 100644 --- a/adb/adb.c +++ b/adb/adb.c
@@ -46,7 +46,6 @@ #endif int HOST = 0; -int gListenAll = 0; static int auth_enabled = 0; @@ -702,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 */ @@ -729,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; @@ -824,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); @@ -845,7 +767,7 @@ l->transport = transport; add_transport_disconnect(l->transport, &l->disconnect); } - return INSTALL_STATUS_OK; + return 0; } } @@ -882,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 @@ -991,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; @@ -1011,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 ); @@ -1107,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 { @@ -1214,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 @@ -1281,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); } } @@ -1575,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); @@ -1641,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 */ @@ -1652,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/charger/Android.mk b/charger/Android.mk index fe0c91d..0258604 100644 --- a/charger/Android.mk +++ b/charger/Android.mk
@@ -12,6 +12,10 @@ LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK endif +ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) +LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND +endif + LOCAL_MODULE := charger LOCAL_MODULE_TAGS := optional LOCAL_FORCE_STATIC_EXECUTABLE := true @@ -21,6 +25,9 @@ LOCAL_C_INCLUDES := bootable/recovery LOCAL_STATIC_LIBRARIES := libminui libpixelflinger_static libpng +ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) +LOCAL_STATIC_LIBRARIES += libsuspend +endif LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils libm libc include $(BUILD_EXECUTABLE)
diff --git a/charger/charger.c b/charger/charger.c index c5e4ec2..353bdf0 100644 --- a/charger/charger.c +++ b/charger/charger.c
@@ -41,6 +41,10 @@ #include <cutils/misc.h> #include <cutils/uevent.h> +#ifdef CHARGER_ENABLE_SUSPEND +#include <suspend/autosuspend.h> +#endif + #include "minui/minui.h" #ifndef max @@ -352,6 +356,21 @@ free(supply); } +#ifdef CHARGER_ENABLE_SUSPEND +static int request_suspend(bool enable) +{ + if (enable) + return autosuspend_enable(); + else + return autosuspend_disable(); +} +#else +static int request_suspend(bool enable) +{ + return 0; +} +#endif + static void parse_uevent(const char *msg, struct uevent *uevent) { uevent->action = ""; @@ -685,6 +704,8 @@ charger->next_screen_transition = -1; gr_fb_blank(true); LOGV("[%lld] animation done\n", now); + if (charger->num_supplies_online > 0) + request_suspend(true); return; } @@ -824,8 +845,10 @@ } } else { /* if the power key got released, force screen state cycle */ - if (key->pending) + if (key->pending) { + request_suspend(false); kick_animation(charger->batt_anim); + } } } @@ -843,6 +866,7 @@ static void handle_power_supply_state(struct charger *charger, int64_t now) { if (charger->num_supplies_online == 0) { + request_suspend(false); if (charger->next_pwr_check == -1) { charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
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/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index 2bcc9c4..538b5be 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 f90af81..7e34da8 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_SHELL 2000 /* adb and debug shell user */ #define AID_CACHE 2001 /* cache access */ @@ -140,7 +139,6 @@ { "net_bw_acct", AID_NET_BW_ACCT, }, { "misc", AID_MISC, }, { "nobody", AID_NOBODY, }, - { "clat", AID_CLAT, }, }; #define android_id_count \ @@ -236,10 +234,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 b20b434..1c80d9c 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) { char *mycon = NULL, *fcon = NULL; @@ -222,6 +230,7 @@ return; } } +#endif NOTICE("starting '%s'\n", svc->name); @@ -258,7 +267,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 = ( @@ -271,9 +282,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)) { @@ -319,12 +332,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) { @@ -351,7 +367,9 @@ _exit(127); } +#ifdef HAVE_SELINUX freecon(scon); +#endif if (pid < 0) { ERROR("failed to start '%s'\n", svc->name); @@ -602,9 +620,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 @@ -752,6 +772,7 @@ } #endif +#ifdef HAVE_SELINUX static const struct selinux_opt seopts_prop[] = { { SELABEL_OPT_PATH, "/data/system/property_contexts" }, { SELABEL_OPT_PATH, "/property_contexts" }, @@ -810,6 +831,8 @@ return 0; } +#endif + int main(int argc, char **argv) { int fd_count = 0; @@ -863,6 +886,7 @@ process_kernel_cmdline(); +#ifdef HAVE_SELINUX union selinux_callback cb; cb.func_log = klog_write; selinux_set_callback(SELINUX_CB_LOG, cb); @@ -887,6 +911,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/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c index 78a9ea9..868230c 100644 --- a/libcorkscrew/arch-arm/ptrace-arm.c +++ b/libcorkscrew/arch-arm/ptrace-arm.c
@@ -29,15 +29,12 @@ static void load_exidx_header(pid_t pid, map_info_t* mi, uintptr_t* out_exidx_start, size_t* out_exidx_size) { uint32_t elf_phoff; - uint32_t elf_phentsize_ehsize; - uint32_t elf_shentsize_phnum; + uint32_t elf_phentsize_phnum; if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff) - && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize), - &elf_phentsize_ehsize) && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum), - &elf_shentsize_phnum)) { - uint32_t elf_phentsize = elf_phentsize_ehsize >> 16; - uint32_t elf_phnum = elf_shentsize_phnum & 0xffff; + &elf_phentsize_phnum)) { + uint32_t elf_phentsize = elf_phentsize_phnum >> 16; + uint32_t elf_phnum = elf_phentsize_phnum & 0xffff; for (uint32_t i = 0; i < elf_phnum; i++) { uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize; uint32_t elf_phdr_type;
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/Android.mk b/libsuspend/Android.mk index 45cb701..a2fa3e0 100644 --- a/libsuspend/Android.mk +++ b/libsuspend/Android.mk
@@ -12,7 +12,6 @@ liblog libcutils include $(CLEAR_VARS) - LOCAL_SRC_FILES := $(libsuspend_src_files) LOCAL_MODULE := libsuspend LOCAL_MODULE_TAGS := optional @@ -21,3 +20,12 @@ LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries) #LOCAL_CFLAGS += -DLOG_NDEBUG=0 include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(libsuspend_src_files) +LOCAL_MODULE := libsuspend +LOCAL_MODULE_TAGS := optional +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES += $(LOCAL_PATH)/include +#LOCAL_CFLAGS += -DLOG_NDEBUG=0 +include $(BUILD_STATIC_LIBRARY)
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/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 5205200..caef358 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 @@ -501,6 +494,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); }