blob: 55e5263f4b60711d80de828ac2f13fb634565f74 [file] [log] [blame]
#include "aos/linux_code/configuration.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <unistd.h>
#include "aos/common/logging/logging.h"
#include "aos/common/unique_malloc_ptr.h"
#include "aos/common/once.h"
namespace aos {
namespace configuration {
namespace {
// Including the terminating '\0'.
const size_t kMaxAddrLength = 18;
// TODO(brians): Don't hard-code this.
const char *const kLinuxNetInterface = "eth0";
const in_addr *DoGetOwnIPAddress() {
static const char *kOverrideVariable = "FRC971_IP_OVERRIDE";
const char *override_ip = getenv(kOverrideVariable);
if (override_ip != NULL) {
static in_addr r;
if (inet_aton(override_ip, &r) != 0) {
return &r;
} else {
LOG(WARNING, "error parsing %s value '%s'\n", kOverrideVariable, override_ip);
}
}
ifaddrs *addrs;
if (getifaddrs(&addrs) != 0) {
LOG(FATAL, "getifaddrs(%p) failed with %d: %s\n", &addrs,
errno, strerror(errno));
}
// Smart pointers don't work very well for iterating through a linked list,
// but it does do a very nice job of making sure that addrs gets freed.
unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
for (; addrs != NULL; addrs = addrs->ifa_next) {
if (addrs->ifa_addr->sa_family == AF_INET) {
if (strcmp(kLinuxNetInterface, addrs->ifa_name) == 0) {
static const in_addr r =
reinterpret_cast<sockaddr_in *>(__builtin_assume_aligned(
addrs->ifa_addr, alignof(sockaddr_in)))->sin_addr;
return &r;
}
}
}
LOG(FATAL, "couldn't find an AF_INET interface named \"%s\"\n",
kLinuxNetInterface);
}
const char *DoGetRootDirectory() {
ssize_t size = 0;
char *r = NULL;
while (true) {
if (r != NULL) delete r;
size += 256;
r = new char[size];
ssize_t ret = readlink("/proc/self/exe", r, size);
if (ret < 0) {
if (ret != -1) {
LOG(WARNING, "it returned %zd, not -1\n", ret);
}
LOG(FATAL, "readlink(\"/proc/self/exe\", %p, %zu) failed with %d: %s\n",
r, size, errno, strerror(errno));
}
if (ret < size) {
void *last_slash = memrchr(r, '/', size);
if (last_slash == NULL) {
r[ret] = '\0';
LOG(FATAL, "couldn't find a '/' in \"%s\"\n", r);
}
*static_cast<char *>(last_slash) = '\0';
LOG(INFO, "got a root dir of \"%s\"\n", r);
return r;
}
}
}
const char *DoGetLoggingDirectory() {
static const char kSuffix[] = "/../../tmp/robot_logs";
const char *root = GetRootDirectory();
char *r = new char[strlen(root) + sizeof(kSuffix)];
strcpy(r, root);
strcat(r, kSuffix);
return r;
}
} // namespace
const char *GetRootDirectory() {
static aos::Once<const char> once(DoGetRootDirectory);
return once.Get();
}
const char *GetLoggingDirectory() {
static aos::Once<const char> once(DoGetLoggingDirectory);
return once.Get();
}
const in_addr &GetOwnIPAddress() {
static aos::Once<const in_addr> once(DoGetOwnIPAddress);
return *once.Get();
}
} // namespace configuration
} // namespace aos