2020-08-12 22:38:15 +00:00
|
|
|
/*
|
|
|
|
* cmd/ifctrstat.c
|
|
|
|
* Purpose: Display statistics about interfaces on the system
|
|
|
|
*
|
|
|
|
* Copyright (c) 2020 Adélie Software in the Public Benefit, Inc.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* This software is provided 'as is' and without any warranty, express or
|
|
|
|
* implied. In no event shall the authors be liable for any damages arising
|
|
|
|
* from the use of this software.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2020-08-14 19:27:23 +00:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdbool.h>
|
2020-08-12 22:38:15 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "libifupdown/libifupdown.h"
|
|
|
|
#include "cmd/multicall.h"
|
|
|
|
|
2020-08-17 19:13:16 +00:00
|
|
|
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
2020-08-12 22:38:15 +00:00
|
|
|
extern int avail_counters_count;
|
|
|
|
|
|
|
|
extern const char *read_counter(const char *interface, const char *counter);
|
|
|
|
|
2020-08-14 19:27:23 +00:00
|
|
|
static bool show_label = true;
|
|
|
|
|
2020-08-12 22:38:15 +00:00
|
|
|
static bool
|
|
|
|
counter_is_valid(const char *candidate)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < avail_counters_count; i++)
|
|
|
|
{
|
2020-08-17 19:13:16 +00:00
|
|
|
if (strcasecmp(avail_counters[i].name, candidate) == 0)
|
2020-08-12 22:38:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-14 15:49:45 +00:00
|
|
|
static void
|
|
|
|
print_counter(const char *iface, const char *name, const char *value)
|
|
|
|
{
|
2020-08-18 20:20:55 +00:00
|
|
|
(void) iface;
|
|
|
|
|
2020-08-14 19:27:23 +00:00
|
|
|
if (show_label)
|
|
|
|
fprintf(stdout, "%s: %s\n", name, value);
|
|
|
|
else
|
|
|
|
fprintf(stdout, "%s\n", value);
|
2020-08-14 15:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
print_all_counters(const char *iface)
|
|
|
|
{
|
|
|
|
int code = EXIT_SUCCESS;
|
|
|
|
const char *res;
|
|
|
|
|
2020-08-18 20:20:55 +00:00
|
|
|
for (int i = 0; i < avail_counters_count; i++)
|
|
|
|
{
|
2020-08-17 19:13:16 +00:00
|
|
|
const char *ctr = avail_counters[i].name;
|
2020-08-14 15:49:45 +00:00
|
|
|
|
|
|
|
res = read_counter(iface, ctr);
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: could not determine value of %s for interface %s: %s\n", argv0, ctr, iface, strerror(errno));
|
|
|
|
code = EXIT_FAILURE;
|
2020-08-18 20:20:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-14 15:49:45 +00:00
|
|
|
print_counter(iface, ctr, res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
2020-08-17 19:59:19 +00:00
|
|
|
static void
|
|
|
|
ifctrstat_list_counters(const char *opt_arg)
|
2020-08-12 22:38:15 +00:00
|
|
|
{
|
|
|
|
(void) opt_arg;
|
|
|
|
|
2020-08-14 15:49:45 +00:00
|
|
|
for (int i = 0; i < avail_counters_count; i++)
|
|
|
|
{
|
2020-08-17 19:13:16 +00:00
|
|
|
fprintf(stdout, "%s\n", avail_counters[i].name);
|
2020-08-12 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2020-08-17 19:59:19 +00:00
|
|
|
static void
|
|
|
|
ifctrstat_set_nolabel(const char *opt_arg)
|
2020-08-14 19:27:23 +00:00
|
|
|
{
|
|
|
|
(void) opt_arg;
|
|
|
|
show_label = false;
|
|
|
|
}
|
|
|
|
|
2020-08-12 22:38:15 +00:00
|
|
|
int
|
2020-08-14 15:49:45 +00:00
|
|
|
ifctrstat_main(int argc, char *argv[])
|
2020-08-12 22:38:15 +00:00
|
|
|
{
|
|
|
|
if (optind >= argc)
|
|
|
|
generic_usage(self_applet, EXIT_FAILURE);
|
|
|
|
|
|
|
|
int idx = optind;
|
2020-08-14 15:49:45 +00:00
|
|
|
if (argc - idx == 0)
|
2020-08-12 22:38:15 +00:00
|
|
|
{
|
2020-08-14 15:49:45 +00:00
|
|
|
fprintf(stderr, "%s: interface required\n",
|
2020-08-12 22:38:15 +00:00
|
|
|
argv0);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *iface = argv[idx++];
|
|
|
|
|
2020-08-14 15:49:45 +00:00
|
|
|
if (argc - idx == 0)
|
|
|
|
{
|
|
|
|
return print_all_counters(iface);
|
|
|
|
}
|
|
|
|
|
2020-08-12 22:38:15 +00:00
|
|
|
for (; idx < argc; idx++)
|
|
|
|
{
|
|
|
|
if (!counter_is_valid(argv[idx]))
|
|
|
|
{
|
2020-08-14 15:49:45 +00:00
|
|
|
fprintf(stderr, "%s: counter %s is not valid or not available\n", argv0, argv[idx]);
|
2020-08-12 22:38:15 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
const char *res = read_counter(iface, argv[idx]);
|
|
|
|
if (!res)
|
|
|
|
{
|
2020-08-14 15:49:45 +00:00
|
|
|
fprintf(stderr, "%s: could not determine value of %s for interface %s: %s\n", argv0, argv[idx], iface, strerror(errno));
|
2020-08-12 22:38:15 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2020-08-14 15:49:45 +00:00
|
|
|
|
|
|
|
print_counter(iface, argv[idx], res);
|
2020-08-12 22:38:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct if_option local_options[] = {
|
2020-08-18 20:36:15 +00:00
|
|
|
{'L', "list", NULL, "list available counters", false, ifctrstat_list_counters},
|
|
|
|
{'n', "no-label", NULL, "print value without counter label", false, ifctrstat_set_nolabel}
|
2020-08-12 22:38:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct if_option_group local_option_group = {
|
|
|
|
.desc = "Program-specific options",
|
|
|
|
.group_size = ARRAY_SIZE(local_options),
|
|
|
|
.group = local_options
|
|
|
|
};
|
|
|
|
|
|
|
|
struct if_applet ifctrstat_applet = {
|
|
|
|
.name = "ifctrstat",
|
|
|
|
.desc = "Display statistics about an interface",
|
2020-08-14 15:49:45 +00:00
|
|
|
.main = ifctrstat_main,
|
2020-08-18 20:36:35 +00:00
|
|
|
.usage = "ifctrstat [options] <interface> <counter>\n ifctrstat [options] --list",
|
|
|
|
.manpage = "8 ifctrstat",
|
2020-08-12 22:38:15 +00:00
|
|
|
.groups = { &global_option_group, &local_option_group, NULL }
|
|
|
|
};
|