blob: 9579316eec793d942f08e63c93a041889c0a7f49 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <getopt.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include "lib/netstack/c/netconfig.h"
void PrintUsage() {
// clang-format off
fprintf(stderr, "Usage: sysinfo <options>...\n");
fprintf(stderr, "\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -l (--hostname) Print the system's hostname \n");
fprintf(stderr, " -4 (--ipv4) Print the system's ipv4 addresses \n");
fprintf(stderr, " -6 (--ipv6) Print the system's ipv6 addresses \n");
fprintf(stderr, " -v (--verbose) Verbose output \n");
fprintf(stderr, " -h (--help) Print usage \n");
putchar('\n');
// clang-format on
}
bool PrintHostname(bool verbose) {
char host_name_buffer[HOST_NAME_MAX + 1];
int result = gethostname(host_name_buffer, sizeof(host_name_buffer));
if (result < 0) {
perror("gethostname failed");
return false;
}
host_name_buffer[sizeof(host_name_buffer) - 1] = '\0';
if (verbose) {
fprintf(stdout, "Host: \t%s\n", host_name_buffer);
} else {
fprintf(stdout, "%s\n", host_name_buffer);
}
return true;
}
bool PrintIPAddresses(bool print_ipv4, bool print_ipv6, bool verbose) {
// create a socket so we can check all the addresses it listens on.
int fd = socket(AF_INET6, SOCK_STREAM, 0);
if (fd < 0) {
perror("unable to create socket");
return false;
}
netc_get_if_info_t get_if_info;
const ssize_t size = ioctl_netc_get_num_ifs(fd, &get_if_info.n_info);
if (size < 0 || get_if_info.n_info == 0) {
perror("no interfaces from ioctl_netc_get_if_info");
close(fd);
return false;
}
for (uint32_t i = 0; i < get_if_info.n_info; ++i) {
const ssize_t size =
ioctl_netc_get_if_info_at(fd, &i, &get_if_info.info[i]);
if (size < 0) {
perror("ioctl_netc_get_if_info_at failed");
close(fd);
return false;
}
netc_if_info_t* if_info = &get_if_info.info[i];
if (if_info->addr.ss_family == AF_INET && print_ipv4) {
sockaddr_in ip4 = *reinterpret_cast<const sockaddr_in*>(&if_info->addr);
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ip4.sin_addr, str, INET_ADDRSTRLEN);
if (verbose) {
fprintf(stdout, "IPv4: \t%s\n", str);
} else {
fprintf(stdout, "%s\n", str);
}
}
if (if_info->addr.ss_family == AF_INET6 && print_ipv6) {
sockaddr_in6 ip6 = *reinterpret_cast<const sockaddr_in6*>(&if_info->addr);
char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ip6.sin6_addr, str, INET6_ADDRSTRLEN);
if (verbose) {
fprintf(stdout, "IPv6: \t%s\n", str);
} else {
fprintf(stdout, "%s\n", str);
}
}
}
close(fd);
return true;
}
int main(int argc, char* const argv[]) {
// clang-format off
static struct option long_options[] = {
{ "hostname", no_argument, 0, 'l' },
{ "ipv4", no_argument, 0, '4' },
{ "ipv6", no_argument, 0, '6' },
{ "help", no_argument, 0, 'h' },
{ "verbose", no_argument, 0, 'v' },
};
// clang-format on
bool opts_done = false;
bool specific = false;
bool print_hostname = false;
bool print_ipv4 = false;
bool print_ipv6 = false;
bool verbose = false;
while (!opts_done) {
switch (getopt_long(argc, argv, "l46hv", long_options, NULL)) {
case 'l':
specific = true;
print_hostname = true;
break;
case '4':
specific = true;
print_ipv4 = true;
break;
case '6':
specific = true;
print_ipv6 = true;
break;
case 'v':
verbose = true;
break;
case 'h':
PrintUsage();
return 0;
case -1:
opts_done = true;
}
}
if (!specific) {
// no specific thing to print, so print all these by default
print_hostname = true;
print_ipv4 = true;
print_ipv6 = true;
verbose = true;
}
if (print_hostname) {
if (!PrintHostname(verbose))
return 1;
}
if (print_ipv4 || print_ipv6) {
if (!PrintIPAddresses(print_ipv4, print_ipv6, verbose))
return 1;
}
return 0;
}