Merge "Added function to explicitly initialize a namespace"
diff --git a/adb/Android.mk b/adb/Android.mk
index 4777883..f1d3bee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -79,10 +79,12 @@
LIBADB_darwin_SRC_FILES := \
get_my_path_darwin.cpp \
+ sysdeps_unix.cpp \
usb_osx.cpp \
LIBADB_linux_SRC_FILES := \
get_my_path_linux.cpp \
+ sysdeps_unix.cpp \
usb_linux.cpp \
LIBADB_windows_SRC_FILES := \
@@ -286,7 +288,11 @@
include $(BUILD_HOST_EXECUTABLE)
-$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,dist_files sdk win_sdk,$(LOCAL_BUILT_MODULE))
+ifdef HOST_CROSS_OS
+# Archive adb.exe for win_sdk build.
+$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
+endif
# adbd device daemon
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 26e376c..3333fc6 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -153,7 +153,9 @@
// - Recursive, so it uses stack space relative to number of directory
// components.
- if (directory_exists(path)) {
+ // If path points to a symlink to a directory, that's fine.
+ struct stat sb;
+ if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
return true;
}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 3a81ce6..cdbff11 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -188,6 +188,7 @@
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
expect_done_ = true;
total_bytes_ += data_length;
+ ReportProgress(rpath, data_length, data_length);
return true;
}
diff --git a/adb/services.cpp b/adb/services.cpp
index 2eef1c2..d5e963b 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -421,6 +421,11 @@
close_on_exec(fd);
disable_tcp_nagle(fd);
+ // Send a TCP keepalive ping to the device every second so we can detect disconnects.
+ if (!set_tcp_keepalive(fd, 1)) {
+ D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
+ }
+
int ret = register_socket_transport(fd, serial.c_str(), port, 0);
if (ret < 0) {
adb_close(fd);
diff --git a/adb/socket.h b/adb/socket.h
index 4083036..9eb1b19 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -114,4 +114,13 @@
void connect_to_remote(asocket *s, const char *destination);
void connect_to_smartsocket(asocket *s);
+// Internal functions that are only made available here for testing purposes.
+namespace internal {
+
+#if ADB_HOST
+char* skip_host_serial(const char* service);
+#endif
+
+} // namespace internal
+
#endif // __ADB_SOCKET_H
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 471ca09..5cbef6d 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -270,3 +270,49 @@
}
#endif // defined(__linux__)
+
+#if ADB_HOST
+
+// Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
+// |expected|, otherwise logs the failure to gtest.
+void VerifySkipHostSerial(const std::string& serial, const char* expected) {
+ const char* result = internal::skip_host_serial(serial.c_str());
+ if (expected == nullptr) {
+ EXPECT_EQ(nullptr, result);
+ } else {
+ EXPECT_STREQ(expected, result);
+ }
+}
+
+// Check [tcp:|udp:]<serial>[:<port>]:<command> format.
+TEST(socket_test, test_skip_host_serial) {
+ for (const std::string& protocol : {"", "tcp:", "udp:"}) {
+ VerifySkipHostSerial(protocol, nullptr);
+ VerifySkipHostSerial(protocol + "foo", nullptr);
+
+ VerifySkipHostSerial(protocol + "foo:bar", ":bar");
+ VerifySkipHostSerial(protocol + "foo:bar:baz", ":bar:baz");
+
+ VerifySkipHostSerial(protocol + "foo:123:bar", ":bar");
+ VerifySkipHostSerial(protocol + "foo:123:456", ":456");
+ VerifySkipHostSerial(protocol + "foo:123:bar:baz", ":bar:baz");
+
+ // Don't register a port unless it's all numbers and ends with ':'.
+ VerifySkipHostSerial(protocol + "foo:123", ":123");
+ VerifySkipHostSerial(protocol + "foo:123bar:baz", ":123bar:baz");
+ }
+}
+
+// Check <prefix>:<serial>:<command> format.
+TEST(socket_test, test_skip_host_serial_prefix) {
+ for (const std::string& prefix : {"usb:", "product:", "model:", "device:"}) {
+ VerifySkipHostSerial(prefix, nullptr);
+ VerifySkipHostSerial(prefix + "foo", nullptr);
+
+ VerifySkipHostSerial(prefix + "foo:bar", ":bar");
+ VerifySkipHostSerial(prefix + "foo:bar:baz", ":bar:baz");
+ VerifySkipHostSerial(prefix + "foo:123:bar", ":123:bar");
+ }
+}
+
+#endif // ADB_HOST
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8e4e93..c083ee1 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <algorithm>
+#include <string>
+#include <vector>
#if !ADB_HOST
#include "cutils/properties.h"
@@ -623,43 +625,43 @@
#if ADB_HOST
-#define PREFIX(str) { str, sizeof(str) - 1 }
-static const struct prefix_struct {
- const char *str;
- const size_t len;
-} prefixes[] = {
- PREFIX("usb:"),
- PREFIX("product:"),
- PREFIX("model:"),
- PREFIX("device:"),
-};
-static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
+namespace internal {
-/* skip_host_serial return the position in a string
- skipping over the 'serial' parameter in the ADB protocol,
- where parameter string may be a host:port string containing
- the protocol delimiter (colon). */
-static char *skip_host_serial(char *service) {
- char *first_colon, *serial_end;
- int i;
+// Returns the position in |service| following the target serial parameter. Serial format can be
+// any of:
+// * [tcp:|udp:]<serial>[:<port>]:<command>
+// * <prefix>:<serial>:<command>
+// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
+//
+// The returned pointer will point to the ':' just before <command>, or nullptr if not found.
+char* skip_host_serial(const char* service) {
+ static const std::vector<std::string>& prefixes =
+ *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});
- for (i = 0; i < num_prefixes; i++) {
- if (!strncmp(service, prefixes[i].str, prefixes[i].len))
- return strchr(service + prefixes[i].len, ':');
+ for (const std::string& prefix : prefixes) {
+ if (!strncmp(service, prefix.c_str(), prefix.length())) {
+ return strchr(service + prefix.length(), ':');
+ }
}
- first_colon = strchr(service, ':');
+ // For fastboot compatibility, ignore protocol prefixes.
+ if (!strncmp(service, "tcp:", 4) || !strncmp(service, "udp:", 4)) {
+ service += 4;
+ }
+
+ char* first_colon = strchr(service, ':');
if (!first_colon) {
- /* No colon in service string. */
- return NULL;
+ // No colon in service string.
+ return nullptr;
}
- serial_end = first_colon;
+
+ char* serial_end = first_colon;
if (isdigit(serial_end[1])) {
serial_end++;
- while ((*serial_end) && isdigit(*serial_end)) {
+ while (*serial_end && isdigit(*serial_end)) {
serial_end++;
}
- if ((*serial_end) != ':') {
+ if (*serial_end != ':') {
// Something other than numbers was found, reset the end.
serial_end = first_colon;
}
@@ -667,6 +669,8 @@
return serial_end;
}
+} // namespace internal
+
#endif // ADB_HOST
static int smart_socket_enqueue(asocket *s, apacket *p)
@@ -725,7 +729,7 @@
service += strlen("host-serial:");
// serial number should follow "host:" and could be a host:port string.
- serial_end = skip_host_serial(service);
+ serial_end = internal::skip_host_serial(service);
if (serial_end) {
*serial_end = 0; // terminate string
serial = service;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 7af2979..ce0f289 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -841,4 +841,9 @@
adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
}
+// Sets TCP socket |fd| to send a keepalive TCP message every |interval_sec| seconds. Set
+// |interval_sec| to 0 to disable keepalives. If keepalives are enabled, the connection will be
+// configured to drop after 10 missed keepalives. Returns true on success.
+bool set_tcp_keepalive(int fd, int interval_sec);
+
#endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_unix.cpp b/adb/sysdeps_unix.cpp
new file mode 100644
index 0000000..4445a44
--- /dev/null
+++ b/adb/sysdeps_unix.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sysdeps.h"
+
+bool set_tcp_keepalive(int fd, int interval_sec) {
+ int enable = (interval_sec > 0);
+ if (adb_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable))) {
+ return false;
+ }
+
+ if (!enable) {
+ return true;
+ }
+
+ // Idle time before sending the first keepalive is TCP_KEEPIDLE on Linux, TCP_KEEPALIVE on Mac.
+#if defined(TCP_KEEPIDLE)
+ if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &interval_sec, sizeof(interval_sec))) {
+ return false;
+ }
+#elif defined(TCP_KEEPALIVE)
+ if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &interval_sec, sizeof(interval_sec))) {
+ return false;
+ }
+#endif
+
+ // TCP_KEEPINTVL and TCP_KEEPCNT are available on Linux 2.4+ and OS X 10.8+ (Mountain Lion).
+#if defined(TCP_KEEPINTVL)
+ if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval_sec, sizeof(interval_sec))) {
+ return false;
+ }
+#endif
+
+#if defined(TCP_KEEPCNT)
+ // On Windows this value is hardcoded to 10. This is a reasonable value, so we do the same here
+ // to match behavior. See SO_KEEPALIVE documentation at
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx.
+ const int keepcnt = 10;
+ if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt))) {
+ return false;
+ }
+#endif
+
+ return true;
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 7eae186..a2f34fb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -1228,6 +1228,33 @@
}
}
+bool set_tcp_keepalive(int fd, int interval_sec) {
+ FH fh = _fh_from_int(fd, __func__);
+
+ if (!fh || fh->clazz != &_fh_socket_class) {
+ D("set_tcp_keepalive(%d) failed: invalid fd", fd);
+ errno = EBADF;
+ return false;
+ }
+
+ tcp_keepalive keepalive;
+ keepalive.onoff = (interval_sec > 0);
+ keepalive.keepalivetime = interval_sec * 1000;
+ keepalive.keepaliveinterval = interval_sec * 1000;
+
+ DWORD bytes_returned = 0;
+ if (WSAIoctl(fh->fh_socket, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), nullptr, 0,
+ &bytes_returned, nullptr, nullptr) != 0) {
+ const DWORD err = WSAGetLastError();
+ D("set_tcp_keepalive(%d) failed: %s", fd,
+ android::base::SystemErrorCodeToString(err).c_str());
+ _socket_set_errno(err);
+ return false;
+ }
+
+ return true;
+}
+
static adb_mutex_t g_console_output_buffer_lock;
void
diff --git a/adb/test_device.py b/adb/test_device.py
index 18174a2..2acc444 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -845,6 +845,72 @@
if host_dir is not None:
shutil.rmtree(host_dir)
+ def test_pull_dir_symlink(self):
+ """Pull a directory into a symlink to a directory.
+
+ Bug: http://b/27362811
+ """
+ if os.name != "posix":
+ raise unittest.SkipTest('requires POSIX')
+
+ try:
+ host_dir = tempfile.mkdtemp()
+ real_dir = os.path.join(host_dir, "dir")
+ symlink = os.path.join(host_dir, "symlink")
+ os.mkdir(real_dir)
+ os.symlink(real_dir, symlink)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+
+ # Populate device directory with random files.
+ temp_files = make_random_device_files(
+ self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+
+ self.device.pull(remote=self.DEVICE_TEMP_DIR, local=symlink)
+
+ for temp_file in temp_files:
+ host_path = os.path.join(
+ real_dir, posixpath.basename(self.DEVICE_TEMP_DIR),
+ temp_file.base_name)
+ self._verify_local(temp_file.checksum, host_path)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ finally:
+ if host_dir is not None:
+ shutil.rmtree(host_dir)
+
+ def test_pull_dir_symlink_collision(self):
+ """Pull a directory into a colliding symlink to directory."""
+ if os.name != "posix":
+ raise unittest.SkipTest('requires POSIX')
+
+ try:
+ host_dir = tempfile.mkdtemp()
+ real_dir = os.path.join(host_dir, "real")
+ tmp_dirname = os.path.basename(self.DEVICE_TEMP_DIR)
+ symlink = os.path.join(host_dir, tmp_dirname)
+ os.mkdir(real_dir)
+ os.symlink(real_dir, symlink)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+
+ # Populate device directory with random files.
+ temp_files = make_random_device_files(
+ self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+
+ self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
+
+ for temp_file in temp_files:
+ host_path = os.path.join(real_dir, temp_file.base_name)
+ self._verify_local(temp_file.checksum, host_path)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ finally:
+ if host_dir is not None:
+ shutil.rmtree(host_dir)
+
def test_pull_symlink_dir(self):
"""Pull a symlink to a directory of symlinks to files."""
try:
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d9180bc..e3340af 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -30,6 +30,7 @@
#include <list>
#include <android-base/logging.h>
+#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -679,11 +680,7 @@
// Check for matching serial number.
if (serial) {
- if ((t->serial && !strcmp(serial, t->serial)) ||
- (t->devpath && !strcmp(serial, t->devpath)) ||
- qual_match(serial, "product:", t->product, false) ||
- qual_match(serial, "model:", t->model, true) ||
- qual_match(serial, "device:", t->device, false)) {
+ if (t->MatchesTarget(serial)) {
if (result) {
*error_out = "more than one device";
if (is_ambiguous) *is_ambiguous = true;
@@ -837,6 +834,43 @@
disconnects_.clear();
}
+bool atransport::MatchesTarget(const std::string& target) const {
+ if (serial) {
+ if (target == serial) {
+ return true;
+ } else if (type == kTransportLocal) {
+ // Local transports can match [tcp:|udp:]<hostname>[:port].
+ const char* local_target_ptr = target.c_str();
+
+ // For fastboot compatibility, ignore protocol prefixes.
+ if (android::base::StartsWith(target, "tcp:") ||
+ android::base::StartsWith(target, "udp:")) {
+ local_target_ptr += 4;
+ }
+
+ // Parse our |serial| and the given |target| to check if the hostnames and ports match.
+ std::string serial_host, error;
+ int serial_port = -1;
+ if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr,
+ &error)) {
+ // |target| may omit the port to default to ours.
+ std::string target_host;
+ int target_port = serial_port;
+ if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
+ nullptr, &error) &&
+ serial_host == target_host && serial_port == target_port) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return (devpath && target == devpath) ||
+ qual_match(target.c_str(), "product:", product, false) ||
+ qual_match(target.c_str(), "model:", model, true) ||
+ qual_match(target.c_str(), "device:", device, false);
+}
+
#if ADB_HOST
static void append_transport_info(std::string* result, const char* key,
diff --git a/adb/transport.h b/adb/transport.h
index 4c0c008..5857249 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -107,6 +107,21 @@
void RemoveDisconnect(adisconnect* disconnect);
void RunDisconnects();
+ // Returns true if |target| matches this transport. A matching |target| can be any of:
+ // * <serial>
+ // * <devpath>
+ // * product:<product>
+ // * model:<model>
+ // * device:<device>
+ //
+ // If this is a local transport, serial will also match [tcp:|udp:]<hostname>[:port] targets.
+ // For example, serial "100.100.100.100:5555" would match any of:
+ // * 100.100.100.100
+ // * tcp:100.100.100.100
+ // * udp:100.100.100.100:5555
+ // This is to make it easier to use the same network target for both fastboot and adb.
+ bool MatchesTarget(const std::string& target) const;
+
private:
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index e6e699b..372bedf 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -225,7 +225,7 @@
static const char _ok_resp[] = "ok";
const int port = (int) (uintptr_t) arg;
- int res, fd;
+ int fd;
char tmp[256];
char con_name[32];
@@ -251,19 +251,19 @@
*/
/* Send the 'accept' request. */
- res = adb_write(fd, _accept_req, strlen(_accept_req));
- if ((size_t)res == strlen(_accept_req)) {
+ if (WriteFdExactly(fd, _accept_req, strlen(_accept_req))) {
/* Wait for the response. In the response we expect 'ok' on success,
* or 'ko' on failure. */
- res = adb_read(fd, tmp, sizeof(tmp));
- if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
+ if (!ReadFdExactly(fd, tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
D("Accepting ADB host connection has failed.");
adb_close(fd);
} else {
/* Host is connected. Register the transport, and start the
* exchange. */
register_socket_transport(fd, "host", port, 1);
- adb_write(fd, _start_req, strlen(_start_req));
+ if (!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
+ adb_close(fd);
+ }
}
/* Prepare for accepting of the next ADB host connection. */
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 1bdea2a..2028ecc 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -218,3 +218,60 @@
ASSERT_EQ(std::string("bar"), t.model);
ASSERT_EQ(std::string("baz"), t.device);
}
+
+TEST(transport, test_matches_target) {
+ std::string serial = "foo";
+ std::string devpath = "/path/to/bar";
+ std::string product = "test_product";
+ std::string model = "test_model";
+ std::string device = "test_device";
+
+ atransport t;
+ t.serial = &serial[0];
+ t.devpath = &devpath[0];
+ t.product = &product[0];
+ t.model = &model[0];
+ t.device = &device[0];
+
+ // These tests should not be affected by the transport type.
+ for (TransportType type : {kTransportAny, kTransportLocal}) {
+ t.type = type;
+
+ EXPECT_TRUE(t.MatchesTarget(serial));
+ EXPECT_TRUE(t.MatchesTarget(devpath));
+ EXPECT_TRUE(t.MatchesTarget("product:" + product));
+ EXPECT_TRUE(t.MatchesTarget("model:" + model));
+ EXPECT_TRUE(t.MatchesTarget("device:" + device));
+
+ // Product, model, and device don't match without the prefix.
+ EXPECT_FALSE(t.MatchesTarget(product));
+ EXPECT_FALSE(t.MatchesTarget(model));
+ EXPECT_FALSE(t.MatchesTarget(device));
+ }
+}
+
+TEST(transport, test_matches_target_local) {
+ std::string serial = "100.100.100.100:5555";
+
+ atransport t;
+ t.serial = &serial[0];
+
+ // Network address matching should only be used for local transports.
+ for (TransportType type : {kTransportAny, kTransportLocal}) {
+ t.type = type;
+ bool should_match = (type == kTransportLocal);
+
+ EXPECT_EQ(should_match, t.MatchesTarget("100.100.100.100"));
+ EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100"));
+ EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100:5555"));
+ EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100"));
+ EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100:5555"));
+
+ // Wrong protocol, hostname, or port should never match.
+ EXPECT_FALSE(t.MatchesTarget("100.100.100"));
+ EXPECT_FALSE(t.MatchesTarget("100.100.100.100:"));
+ EXPECT_FALSE(t.MatchesTarget("100.100.100.100:-1"));
+ EXPECT_FALSE(t.MatchesTarget("100.100.100.100:5554"));
+ EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100"));
+ }
+}
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 31d9f0f..d993576 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -189,7 +189,7 @@
return true;
}
-bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
+bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid __unused,
FilePath *crash_directory,
bool *out_of_capacity) {
if (out_of_capacity) *out_of_capacity = false;
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index a326f55..1b4ecbe 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -90,7 +90,11 @@
ifeq ($(HOST_OS),linux)
my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
endif
-$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
+ifdef HOST_CROSS_OS
+# Archive fastboot.exe for win_sdk build.
+$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
+endif
my_dist_files :=
ifeq ($(HOST_OS),linux)
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index 22ca706..5f2396b 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -106,14 +106,14 @@
ResetValue();
// Since the value is null, default value will be returned
- int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
}
// Trivial case => get returns what was set
{
- int len = SetAndGetProperty("hello_world");
+ size_t len = SetAndGetProperty("hello_world");
EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
EXPECT_STREQ("hello_world", mValue);
ResetValue();
@@ -122,7 +122,7 @@
// Set to empty string => get returns default always
{
const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
- int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+ size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
ResetValue();
@@ -147,7 +147,7 @@
// Expect that the value set fails since it's too long
EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
- int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
EXPECT_STREQ(VALID_TEST_VALUE, mValue);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index ee883f0..607d667 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -14,15 +14,16 @@
// limitations under the License.
//
-liblog_host_sources = [
+liblog_sources = [
"logd_write.c",
+ "log_event_list.c",
"log_event_write.c",
+]
+liblog_host_sources = [
"fake_log_device.c",
//"event.logtags",
]
liblog_target_sources = [
- "logd_write.c",
- "log_event_write.c",
"event_tag_map.c",
"log_time.cpp",
"log_is_loggable.c",
@@ -36,6 +37,8 @@
name: "liblog",
host_supported: true,
+ srcs: liblog_sources,
+
target: {
host: {
srcs: liblog_host_sources,
@@ -71,7 +74,6 @@
// $(LOCAL_PATH)/event.logtags)
// so make sure we do not regret hard-coding it as follows:
"-DLIBLOG_LOG_TAG=1005",
- "-DSNET_EVENT_LOG_TAG=1397638484",
],
compile_multilib: "both",
stl: "none",
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 0badbd9..3d58147 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -14,66 +14,9 @@
* limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/cdefs.h>
-
#include <gtest/gtest.h>
-// Should be in bionic test suite, *but* we are using liblog to confirm
-// end-to-end logging, so let the overly cute oedipus complex begin ...
-#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
-#define _ANDROID_LOG_H // Priorities redefined
-#define _LIBS_LOG_LOG_H // log ids redefined
-typedef unsigned char log_id_t; // log_id_t missing as a result
-#define _LIBS_LOG_LOG_READ_H // log_time redefined
-
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-
-TEST(libc, __libc_fatal_no_abort) {
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- char b[80];
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
- snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((int)log_msg.id() != LOG_ID_CRASH) {
- continue;
- }
-
- char *data = log_msg.msg();
-
- if ((*data == ANDROID_LOG_FATAL)
- && !strcmp(data + 1, "libc")
- && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
- ++count;
- }
- }
-
- EXPECT_EQ(1, count);
-
- android_logger_list_close(logger_list);
-}
+#include <stdio.h>
TEST(libc, __pstore_append) {
FILE *fp;
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 7906986..09fbbb1 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -14,5 +14,4 @@
LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
-include $(LOCAL_PATH)/tools/Android.mk \
- $(LOCAL_PATH)/test/Android.mk
+include $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
deleted file mode 100644
index f403621..0000000
--- a/libmincrypt/tools/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Determine whether to build dumpkey from system/core/libmincrypt or from
-# bootable/recovery/tools. The dumpkey source is temporarily present in both
-# locations during the process of moving the tool to the recovery repository.
-# TODO(mnissler): Remove the guard after the transition is complete.
-ifndef BUILD_DUMPKEY_FROM_RECOVERY
-BUILD_DUMPKEY_FROM_RECOVERY := false
-endif
-
-ifeq ($(BUILD_DUMPKEY_FROM_RECOVERY),false)
-include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
-endif
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
deleted file mode 100644
index 3eb1398..0000000
--- a/libmincrypt/tools/DumpPublicKey.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumpkey;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import java.io.FileInputStream;
-import java.math.BigInteger;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.KeyStore;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.ECPoint;
-
-/**
- * Command line tool to extract RSA public keys from X.509 certificates
- * and output source code with data initializers for the keys.
- * @hide
- */
-class DumpPublicKey {
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 1: 2048-bit RSA key with e=3 and SHA-1 hash
- * 2: 2048-bit RSA key with e=65537 and SHA-1 hash
- * 3: 2048-bit RSA key with e=3 and SHA-256 hash
- * 4: 2048-bit RSA key with e=65537 and SHA-256 hash
- * @throws Exception if the key has the wrong size or public exponent
- */
- static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
- BigInteger pubexp = key.getPublicExponent();
- BigInteger modulus = key.getModulus();
- int version;
-
- if (pubexp.equals(BigInteger.valueOf(3))) {
- version = useSHA256 ? 3 : 1;
- } else if (pubexp.equals(BigInteger.valueOf(65537))) {
- version = useSHA256 ? 4 : 2;
- } else {
- throw new Exception("Public exponent should be 3 or 65537 but is " +
- pubexp.toString(10) + ".");
- }
-
- if (modulus.bitLength() != 2048) {
- throw new Exception("Modulus should be 2048 bits long but is " +
- modulus.bitLength() + " bits.");
- }
-
- return version;
- }
-
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 5: 256-bit EC key with curve NIST P-256
- * @throws Exception if the key has the wrong size or public exponent
- */
- static int checkEC(ECPublicKey key) throws Exception {
- if (key.getParams().getCurve().getField().getFieldSize() != 256) {
- throw new Exception("Curve must be NIST P-256");
- }
-
- return 5;
- }
-
- /**
- * Perform sanity check on public key.
- */
- static int check(PublicKey key, boolean useSHA256) throws Exception {
- if (key instanceof RSAPublicKey) {
- return checkRSA((RSAPublicKey) key, useSHA256);
- } else if (key instanceof ECPublicKey) {
- if (!useSHA256) {
- throw new Exception("Must use SHA-256 with EC keys!");
- }
- return checkEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
-
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
- int version = check(key, useSHA256);
-
- BigInteger N = key.getModulus();
-
- StringBuilder result = new StringBuilder();
-
- int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
-
- if (version > 1) {
- result.append("v");
- result.append(Integer.toString(version));
- result.append(" ");
- }
-
- result.append("{");
- result.append(nwords);
-
- BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
- BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
-
- result.append(",0x");
- result.append(N0inv.toString(16));
-
- BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
- BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
-
- // Write out modulus as little endian array of integers.
- result.append(",{");
- for (int i = 0; i < nwords; ++i) {
- long n = N.mod(B).longValue();
- result.append(n);
-
- if (i != nwords - 1) {
- result.append(",");
- }
-
- N = N.divide(B);
- }
- result.append("}");
-
- // Write R^2 as little endian array of integers.
- result.append(",{");
- for (int i = 0; i < nwords; ++i) {
- long rr = RR.mod(B).longValue();
- result.append(rr);
-
- if (i != nwords - 1) {
- result.append(",");
- }
-
- RR = RR.divide(B);
- }
- result.append("}");
-
- result.append("}");
- return result.toString();
- }
-
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printEC(ECPublicKey key) throws Exception {
- int version = checkEC(key);
-
- StringBuilder result = new StringBuilder();
-
- result.append("v");
- result.append(Integer.toString(version));
- result.append(" ");
-
- BigInteger X = key.getW().getAffineX();
- BigInteger Y = key.getW().getAffineY();
- int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate
-
- result.append("{");
- result.append(nbytes);
-
- BigInteger B = BigInteger.valueOf(0x100L); // 2^8
-
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = X.mod(B).longValue();
- result.append(n);
-
- if (i != nbytes - 1) {
- result.append(",");
- }
-
- X = X.divide(B);
- }
- result.append("}");
-
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = Y.mod(B).longValue();
- result.append(n);
-
- if (i != nbytes - 1) {
- result.append(",");
- }
-
- Y = Y.divide(B);
- }
- result.append("}");
-
- result.append("}");
- return result.toString();
- }
-
- static String print(PublicKey key, boolean useSHA256) throws Exception {
- if (key instanceof RSAPublicKey) {
- return printRSA((RSAPublicKey) key, useSHA256);
- } else if (key instanceof ECPublicKey) {
- return printEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
-
- public static void main(String[] args) {
- if (args.length < 1) {
- System.err.println("Usage: DumpPublicKey certfile ... > source.c");
- System.exit(1);
- }
- Security.addProvider(new BouncyCastleProvider());
- try {
- for (int i = 0; i < args.length; i++) {
- FileInputStream input = new FileInputStream(args[i]);
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-
- boolean useSHA256 = false;
- String sigAlg = cert.getSigAlgName();
- if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
- // SignApk has historically accepted "MD5withRSA"
- // certificates, but treated them as "SHA1withRSA"
- // anyway. Continue to do so for backwards
- // compatibility.
- useSHA256 = false;
- } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
- useSHA256 = true;
- } else {
- System.err.println(args[i] + ": unsupported signature algorithm \"" +
- sigAlg + "\"");
- System.exit(1);
- }
-
- PublicKey key = cert.getPublicKey();
- check(key, useSHA256);
- System.out.print(print(key, useSHA256));
- System.out.println(i < args.length - 1 ? "," : "");
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- System.exit(0);
- }
-}
diff --git a/libmincrypt/tools/DumpPublicKey.mf b/libmincrypt/tools/DumpPublicKey.mf
deleted file mode 100644
index 7bb3bc8..0000000
--- a/libmincrypt/tools/DumpPublicKey.mf
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: com.android.dumpkey.DumpPublicKey
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d9b32f9..24ecf86 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -89,9 +89,9 @@
vector.add(4);
vector.setCapacity(8);
- ASSERT_EQ(8, vector.capacity());
+ ASSERT_EQ(8U, vector.capacity());
vector.setCapacity(2);
- ASSERT_EQ(8, vector.capacity());
+ ASSERT_EQ(8U, vector.capacity());
}
// NOTE: All of the tests below are useless because of the "TODO" above.
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 230dd11..4eb5e83 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -99,11 +99,20 @@
}
void LogAudit::enforceIntegrity() {
+ static bool loggedOnce;
+ bool once = loggedOnce;
+
+ loggedOnce = true;
+
if (!AUDITD_ENFORCE_INTEGRITY) {
- logToDmesg("integrity enforcement suppressed; not rebooting");
+ if (!once) {
+ logToDmesg("integrity enforcement suppressed; not rebooting");
+ }
} else if (rebootToSafeMode) {
if (getProperty("persist.sys.safemode") == "1") {
- logToDmesg("integrity enforcement suppressed; in safe mode");
+ if (!once) {
+ logToDmesg("integrity enforcement suppressed; in safe mode");
+ }
return;
}
@@ -155,6 +164,10 @@
}
}
+ // Note: The audit log can include untrusted strings, but those containing
+ // "a control character, unprintable character, double quote mark, or a
+ // space" are hex encoded. The space character before the search term is
+ // therefore needed to prevent denial of service. Do not remove the space.
bool permissive = strstr(str, " enforcing=0") ||
strstr(str, " permissive=1");
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index a4b96d3..2a04880 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -90,7 +90,7 @@
while(it != times.end()) {
if (*it == me) {
times.erase(it);
- me->release_Locked();
+ me->release_nodelete_Locked();
break;
}
it++;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index f5969df..b66ff9e 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -75,7 +75,13 @@
void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; }
void cleanSkip_Locked(void);
- // Called after LogTimeEntry removed from list, lock implicitly held
+ // These called after LogTimeEntry removed from list, lock implicitly held
+ void release_nodelete_Locked(void) {
+ mRelease = true;
+ pthread_cond_signal(&threadTriggeredCondition);
+ // assumes caller code path will call decRef_Locked()
+ }
+
void release_Locked(void) {
mRelease = true;
pthread_cond_signal(&threadTriggeredCondition);
diff --git a/logd/main.cpp b/logd/main.cpp
index f4d7464..3095f7f 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -165,7 +165,7 @@
char newkey[PROPERTY_KEY_MAX];
snprintf(newkey, sizeof(newkey), "ro.%s", key);
property_get(newkey, property, "");
- // persist properties set by /data require innoculation with
+ // persist properties set by /data require inoculation with
// logd-reinit. They may be set in init.rc early and function, but
// otherwise are defunct unless reset. Do not rely on persist
// properties for startup-only keys unless you are willing to restart
@@ -265,8 +265,11 @@
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
- setgid(AID_SYSTEM);
- setuid(AID_SYSTEM);
+ // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
+ // else, we have even lesser privileges and accept our fate. Not worth
+ // checking for error returns setting this thread's privileges.
+ (void)setgid(AID_SYSTEM);
+ (void)setuid(AID_SYSTEM);
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index aea2585..f95d703 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -19,6 +19,7 @@
from os import fstat
from struct import pack
from hashlib import sha1
+import sys
def filesize(f):
if f is None:
@@ -133,8 +134,10 @@
img_id = write_header(args)
write_data(args)
if args.id:
- print('0x' + ''.join('{:02x}'.format(ord(c)) for c in img_id))
-
+ if isinstance(img_id, str):
+ # Python 2's struct.pack returns a string, but py3 returns bytes.
+ img_id = [ord(x) for x in img_id]
+ print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
if __name__ == '__main__':
main()
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index 30485a0..a2b9111 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -16,6 +16,7 @@
#
# pylint: disable=bad-indentation,bad-continuation
+from __future__ import print_function
import os
import re
import sys
@@ -72,11 +73,11 @@
ff_list.append(name)
def Dump(struct_name, values):
- print 'static struct label %s[] = {' % (struct_name)
+ print('static struct label %s[] = {' % (struct_name))
for value in values:
- print ' LABEL(%s),' % (value)
- print ' LABEL_END,'
- print '};'
+ print(' LABEL(%s),' % (value))
+ print(' LABEL_END,')
+ print('};')
Dump("input_prop_labels", input_prop_list)
Dump("ev_labels", ev_list)
diff --git a/toolbox/top.c b/toolbox/top.c
index 0ea5a5e..6fda132 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -62,12 +62,13 @@
char state;
uint64_t utime;
uint64_t stime;
+ char pr[3];
+ long ni;
uint64_t delta_utime;
uint64_t delta_stime;
uint64_t delta_time;
uint64_t vss;
uint64_t rss;
- int prs;
int num_threads;
char policy[POLICY_NAME_LEN];
};
@@ -183,11 +184,11 @@
old_procs = new_procs;
num_old_procs = num_new_procs;
memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
- sleep(delay);
read_procs();
print_procs();
free_old_procs();
fflush(stdout);
+ if (iterations != 0) sleep(delay);
}
return 0;
@@ -339,20 +340,30 @@
strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
proc->tname[THREAD_NAME_LEN-1] = 0;
- /* Scan rest of string. */
+ // Scan rest of string.
+ long pr;
sscanf(close_paren + 1,
- " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%" SCNu64
- "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d "
- "%" SCNu64
- "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%d",
+ " %c "
+ "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%" SCNu64 // utime %lu (14)
+ "%" SCNu64 // stime %lu (15)
+ "%*d %*d "
+ "%ld " // priority %ld (18)
+ "%ld " // nice %ld (19)
+ "%*d %*d %*d "
+ "%" SCNu64 // vsize %lu (23)
+ "%" SCNu64, // rss %ld (24)
&proc->state,
&proc->utime,
&proc->stime,
+ &pr,
+ &proc->ni,
&proc->vss,
- &proc->rss,
- &proc->prs);
+ &proc->rss);
+
+ // Translate the PR field.
+ if (pr < -9) strcpy(proc->pr, "RT");
+ else snprintf(proc->pr, sizeof(proc->pr), "%ld", pr);
return 0;
}
@@ -414,11 +425,10 @@
}
static void print_procs(void) {
+ static int call = 0;
int i;
struct proc_info *old_proc, *proc;
long unsigned total_delta_time;
- struct passwd *user;
- char *user_str, user_buf[20];
for (i = 0; i < num_new_procs; i++) {
if (new_procs[i]) {
@@ -441,7 +451,7 @@
qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
- printf("\n\n\n");
+ if (call++ > 0) printf("\n\n\n");
printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
@@ -459,16 +469,18 @@
total_delta_time);
printf("\n");
if (!threads)
- printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
+ printf("%5s %-8s %2s %3s %4s %1s %5s %7s %7s %3s %s\n", "PID", "USER", "PR", "NI", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "Name");
else
- printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
+ printf("%5s %5s %-8s %2s %3s %4s %1s %7s %7s %3s %-15s %s\n", "PID", "TID", "USER", "PR", "NI", "CPU%", "S", "VSS", "RSS", "PCY", "Thread", "Proc");
for (i = 0; i < num_new_procs; i++) {
proc = new_procs[i];
if (!proc || (max_procs && (i >= max_procs)))
break;
- user = getpwuid(proc->uid);
+ struct passwd* user = getpwuid(proc->uid);
+ char user_buf[20];
+ char* user_str;
if (user && user->pw_name) {
user_str = user->pw_name;
} else {
@@ -476,13 +488,17 @@
user_str = user_buf;
}
if (!threads) {
- printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n",
- proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+ printf("%5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %s\n",
+ proc->pid, user_str, proc->pr, proc->ni,
+ proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
+ proc->name[0] != 0 ? proc->name : proc->tname);
} else {
- printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n",
- proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
+ printf("%5d %5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-15s %s\n",
+ proc->pid, proc->tid, user_str, proc->pr, proc->ni,
+ proc->delta_time * 100 / total_delta_time, proc->state,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
+ proc->tname, proc->name);
}
}
}