Merge "Define LIKELY and UNLIKELY in a vendor friendly way"
diff --git a/adb/adb.h b/adb/adb.h
index 59644d4..ea20800 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 35
+#define ADB_SERVER_VERSION 36
class atransport;
struct usb_handle;
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 21a82e8..611b239 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -37,7 +37,13 @@
// fds far from the range that open() returns. But all of that might defeat the
// purpose of the tests.
-TEST(io, ReadFdExactly_whole) {
+#if defined(_WIN32)
+#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y)
+#else
+#define POSIX_TEST TEST
+#endif
+
+POSIX_TEST(io, ReadFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -51,7 +57,7 @@
EXPECT_STREQ(expected, buf);
}
-TEST(io, ReadFdExactly_eof) {
+POSIX_TEST(io, ReadFdExactly_eof) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -65,7 +71,7 @@
EXPECT_EQ(0, errno) << strerror(errno);
}
-TEST(io, ReadFdExactly_partial) {
+POSIX_TEST(io, ReadFdExactly_partial) {
const char input[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -82,7 +88,7 @@
EXPECT_STREQ(expected.c_str(), buf);
}
-TEST(io, WriteFdExactly_whole) {
+POSIX_TEST(io, WriteFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -97,7 +103,7 @@
EXPECT_STREQ(expected, s.c_str());
}
-TEST(io, WriteFdExactly_partial) {
+POSIX_TEST(io, WriteFdExactly_partial) {
const char buf[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -114,7 +120,7 @@
EXPECT_EQ(expected, s);
}
-TEST(io, WriteFdExactly_ENOSPC) {
+POSIX_TEST(io, WriteFdExactly_ENOSPC) {
int fd = open("/dev/full", O_WRONLY);
ASSERT_NE(-1, fd);
@@ -123,7 +129,7 @@
ASSERT_EQ(ENOSPC, errno);
}
-TEST(io, WriteFdExactly_string) {
+POSIX_TEST(io, WriteFdExactly_string) {
const char str[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -137,7 +143,7 @@
EXPECT_STREQ(str, s.c_str());
}
-TEST(io, WriteFdFmt) {
+POSIX_TEST(io, WriteFdFmt) {
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 78efea8..f0c334e 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -215,3 +215,32 @@
// Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
}
+
+TEST_F(sysdeps_poll, fd_count) {
+ // https://code.google.com/p/android/issues/detail?id=12141
+ static constexpr int num_sockets = 512;
+ std::vector<int> sockets;
+ std::vector<adb_pollfd> pfds;
+ sockets.resize(num_sockets * 2);
+ for (int32_t i = 0; i < num_sockets; ++i) {
+ ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno);
+ ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i)));
+ adb_pollfd pfd;
+ pfd.events = POLLIN;
+ pfd.fd = sockets[i * 2 + 1];
+ pfds.push_back(pfd);
+ }
+
+ ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0));
+ for (int i = 0; i < num_sockets; ++i) {
+ ASSERT_NE(0, pfds[i].revents & POLLIN);
+
+ int32_t buf[2] = { -1, -1 };
+ ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast<ssize_t>(sizeof(int32_t)));
+ ASSERT_EQ(i, buf[0]);
+ }
+
+ for (int fd : sockets) {
+ adb_close(fd);
+ }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a2f34fb..bc09fdc 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -191,7 +191,7 @@
#define fh_socket u.socket
#define WIN32_FH_BASE 2048
-#define WIN32_MAX_FHS 128
+#define WIN32_MAX_FHS 2048
static adb_mutex_t _win32_lock;
static FHRec _win32_fhs[ WIN32_MAX_FHS ];
diff --git a/adb/transport.cpp b/adb/transport.cpp
index aaab21d..1cf4c49 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -295,20 +295,12 @@
transport_unref(t);
}
-static void kick_transport_locked(atransport* t) {
- CHECK(t != nullptr);
- if (!t->kicked) {
- t->kicked = true;
- t->kick(t);
- }
-}
-
void kick_transport(atransport* t) {
adb_mutex_lock(&transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid,
// check if the transport is in transport_list first.
if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
- kick_transport_locked(t);
+ t->Kick();
}
adb_mutex_unlock(&transport_lock);
}
@@ -621,7 +613,7 @@
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial);
- kick_transport_locked(t);
+ t->Kick();
t->close(t);
remove_transport(t);
} else {
@@ -748,6 +740,14 @@
return result;
}
+void atransport::Kick() {
+ if (!kicked_) {
+ kicked_ = true;
+ CHECK(kick_func_ != nullptr);
+ kick_func_(this);
+ }
+}
+
const std::string atransport::connection_state_name() const {
switch (connection_state) {
case kCsOffline: return "offline";
@@ -928,10 +928,7 @@
void close_usb_devices() {
adb_mutex_lock(&transport_lock);
for (const auto& t : transport_list) {
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
+ t->Kick();
}
adb_mutex_unlock(&transport_lock);
}
@@ -1002,7 +999,7 @@
// the read_transport thread will notify the main thread to make this transport
// offline. Then the main thread will notify the write_transport thread to exit.
// Finally, this transport will be closed and freed in the main thread.
- kick_transport_locked(t);
+ t->Kick();
}
}
adb_mutex_unlock(&transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index 5857249..35d7b50 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -60,7 +60,13 @@
int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
void (*close)(atransport* t) = nullptr;
- void (*kick)(atransport* t) = nullptr;
+ void SetKickFunction(void (*kick_func)(atransport*)) {
+ kick_func_ = kick_func;
+ }
+ bool IsKicked() {
+ return kicked_;
+ }
+ void Kick();
int fd = -1;
int transport_socket = -1;
@@ -82,7 +88,6 @@
char* device = nullptr;
char* devpath = nullptr;
int adb_port = -1; // Use for emulators (local transport)
- bool kicked = false;
void* key = nullptr;
unsigned char token[TOKEN_SIZE] = {};
@@ -123,6 +128,9 @@
bool MatchesTarget(const std::string& target) const;
private:
+ bool kicked_ = false;
+ void (*kick_func_)(atransport*) = nullptr;
+
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
FeatureSet features_;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index f6c9df4..4121f47 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,7 +388,7 @@
{
int fail = 0;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->close = remote_close;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2028ecc..a6db07a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,47 +20,6 @@
#include "adb.h"
-class TestTransport : public atransport {
-public:
- bool operator==(const atransport& rhs) const {
- EXPECT_EQ(read_from_remote, rhs.read_from_remote);
- EXPECT_EQ(write_to_remote, rhs.write_to_remote);
- EXPECT_EQ(close, rhs.close);
- EXPECT_EQ(kick, rhs.kick);
-
- EXPECT_EQ(fd, rhs.fd);
- EXPECT_EQ(transport_socket, rhs.transport_socket);
-
- EXPECT_EQ(
- 0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
-
- EXPECT_EQ(ref_count, rhs.ref_count);
- EXPECT_EQ(sync_token, rhs.sync_token);
- EXPECT_EQ(connection_state, rhs.connection_state);
- EXPECT_EQ(online, rhs.online);
- EXPECT_EQ(type, rhs.type);
-
- EXPECT_EQ(usb, rhs.usb);
- EXPECT_EQ(sfd, rhs.sfd);
-
- EXPECT_EQ(serial, rhs.serial);
- EXPECT_EQ(product, rhs.product);
- EXPECT_EQ(model, rhs.model);
- EXPECT_EQ(device, rhs.device);
- EXPECT_EQ(devpath, rhs.devpath);
- EXPECT_EQ(adb_port, rhs.adb_port);
- EXPECT_EQ(kicked, rhs.kicked);
-
- EXPECT_EQ(key, rhs.key);
- EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
- EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
-
- EXPECT_EQ(features(), rhs.features());
-
- return true;
- }
-};
-
class TransportSetup {
public:
TransportSetup() {
@@ -83,35 +42,19 @@
static TransportSetup g_TransportSetup;
TEST(transport, kick_transport) {
- TestTransport t;
-
+ atransport t;
+ static size_t kick_count;
+ kick_count = 0;
// Mutate some member so we can test that the function is run.
- t.kick = [](atransport* trans) { trans->fd = 42; };
-
- TestTransport expected;
- expected.kick = t.kick;
- expected.fd = 42;
- expected.kicked = 1;
-
- kick_transport(&t);
- ASSERT_EQ(42, t.fd);
- ASSERT_EQ(1, t.kicked);
- ASSERT_EQ(expected, t);
-}
-
-TEST(transport, kick_transport_already_kicked) {
- // Ensure that the transport is not modified if the transport has already been
- // kicked.
- TestTransport t;
- t.kicked = 1;
- t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
-
- TestTransport expected;
- expected.kicked = 1;
- expected.kick = t.kick;
-
- kick_transport(&t);
- ASSERT_EQ(expected, t);
+ t.SetKickFunction([](atransport* trans) { kick_count++; });
+ ASSERT_FALSE(t.IsKicked());
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
+ // A transport can only be kicked once.
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
}
static void DisconnectFunc(void* arg, atransport*) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 263f9e7..d05d928 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -84,7 +84,7 @@
{
D("transport: usb");
t->close = remote_close;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 79a5670..bd8d5af 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -63,7 +63,6 @@
static void refresh_cache(struct cache *cache, const char *key)
{
- uint32_t serial;
char buf[PROP_VALUE_MAX];
if (!cache->pinfo) {
@@ -71,13 +70,8 @@
if (!cache->pinfo) {
return;
}
- cache->serial = -1;
}
- serial = __system_property_serial(cache->pinfo);
- if (serial == cache->serial) {
- return;
- }
- cache->serial = serial;
+ cache->serial = __system_property_serial(cache->pinfo);
__system_property_read(cache->pinfo, 0, buf);
switch(buf[0]) {
case 't': case 'T':
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 456f8b3..1a7d4aa 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1338,7 +1338,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, levels[j].level));
}
@@ -1347,7 +1347,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, levels[j].level));
}
@@ -1379,7 +1379,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1388,7 +1388,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1408,7 +1408,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1417,7 +1417,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1439,7 +1439,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1448,7 +1448,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1468,7 +1468,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1477,7 +1477,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1513,7 +1513,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1522,7 +1522,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1542,7 +1542,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1551,7 +1551,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 8b32418..85f9415 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -32,7 +32,6 @@
OUR_TOOLS := \
getevent \
- iftop \
ioctl \
log \
nandread \
diff --git a/toolbox/iftop.c b/toolbox/iftop.c
deleted file mode 100644
index 800c0f0..0000000
--- a/toolbox/iftop.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#define PROC_NET_DEV "/proc/net/dev"
-
-#define MAX_IF 8 /* max interfaces we can handle */
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-#define _STR(s) #s
-#define STR(s) _STR(s)
-
-struct if_stats {
- char name[IFNAMSIZ];
-
- unsigned int mtu;
-
- unsigned int rx_bytes;
- unsigned int rx_packets;
- unsigned int rx_errors;
- unsigned int rx_dropped;
-
- unsigned int tx_bytes;
- unsigned int tx_packets;
- unsigned int tx_errors;
- unsigned int tx_dropped;
-};
-
-static int get_mtu(const char *if_name)
-{
- struct ifreq ifr;
- int s, ret;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&ifr, 0, sizeof(struct ifreq));
- ifr.ifr_addr.sa_family = AF_INET;
- strcpy(ifr.ifr_name, if_name);
-
- ret = ioctl(s, SIOCGIFMTU, &ifr);
- if (ret < 0) {
- perror("ioctl");
- exit(EXIT_FAILURE);
- }
-
- ret = close(s);
- if (ret < 0) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return ifr.ifr_mtu;
-}
-
-static int get_interfaces(struct if_stats *ifs)
-{
- char buf[PAGE_SIZE];
- char *p;
- int ret, nr, fd;
-
- fd = open(PROC_NET_DEV, O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- if (ret < 0) {
- perror("read");
- exit(EXIT_FAILURE);
- } else if (!ret) {
- fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
- exit(EXIT_FAILURE);
- }
- buf[ret] = '\0';
-
- /* skip down to the third line */
- p = strchr(buf, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p = strchr(p + 1, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p += 1;
-
- /*
- * Key:
- * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
- * (Tx) bytes packets errs drop fifo colls carrier compressed
- */
- for (nr = 0; nr < MAX_IF; nr++) {
- char *c;
-
- ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
- if (ret != 1) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- /*
- * This works around a bug in the proc file where large interface names
- * or Rx byte counts eat the delimiter, breaking sscanf.
- */
- c = strchr(ifs->name, ':');
- if (c)
- *c = '\0';
-
- p = strchr(p, ':') + 1;
-
- ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
- "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
- &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
- &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
- if (ret != 8) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- ifs->mtu = get_mtu(ifs->name);
-
- p = strchr(p, '\n') + 1;
- if (*p == '\0') {
- nr++;
- break;
- }
-
- ifs++;
- }
-
- ret = close(fd);
- if (ret) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return nr;
-}
-
-static void print_header(void)
-{
- printf(" Rx Tx\n");
- printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
- "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
- "packets", "errs", "drpd");
-}
-
-static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
-{
- int i = 0;
-
- while (nr--) {
- if (old->rx_packets || old->tx_packets) {
- printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
- new->name, new->mtu,
- new->rx_bytes - old->rx_bytes,
- new->rx_packets - old->rx_packets,
- new->rx_errors - old->rx_errors,
- new->rx_dropped - old->rx_dropped,
- new->tx_bytes - old->tx_bytes,
- new->tx_packets - old->tx_packets,
- new->tx_errors - old->tx_errors,
- new->tx_dropped - old->tx_dropped);
- i++;
- }
- old++;
- new++;
- }
-
- return i;
-}
-
-static void usage(const char *cmd)
-{
- fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
-}
-
-int iftop_main(int argc, char *argv[])
-{
- struct if_stats ifs[2][MAX_IF];
- int count = 0, header_interval = 22, delay = 1, i;
- unsigned int toggle = 0;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -d requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- delay = atoi(argv[i++]);
- if (!delay)
- delay = 1;
- continue;
- }
- if (!strcmp(argv[i], "-r")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -r requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- header_interval = atoi(argv[i++]);
- if (header_interval < MAX_IF)
- header_interval = MAX_IF;
- continue;
- }
- if (!strcmp(argv[i], "-h")) {
- usage(argv[0]);
- exit(EXIT_SUCCESS);
- }
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- get_interfaces(ifs[!toggle]);
- if (header_interval)
- print_header();
- while (1) {
- int nr;
-
- sleep(delay);
- nr = get_interfaces(ifs[toggle]);
- if (header_interval && count + nr > header_interval) {
- print_header();
- count = 0;
- }
- count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
- toggle = !toggle;
- }
-
- return 0;
-}