ifctrstat: Add ability to output counter values
This commit is contained in:
		
							parent
							
								
									95d943ee44
								
							
						
					
					
						commit
						6106164d7c
					
				
					 3 changed files with 111 additions and 17 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -62,7 +62,7 @@ MULTICALL_${CONFIG_IFQUERY}_OBJ += ${IFQUERY_SRC:.c=.o} | |||
| CMDS_${CONFIG_IFQUERY} += ifquery | ||||
| CPPFLAGS_${CONFIG_IFQUERY} += -DCONFIG_IFQUERY | ||||
| 
 | ||||
| # enable ifctrstat applet (+9 KB)
 | ||||
| # enable ifctrstat applet (+16 KB)
 | ||||
| CONFIG_IFCTRSTAT ?= Y | ||||
| IFCTRSTAT_SRC = cmd/ifctrstat.c cmd/ifctrstat-${LAYOUT}.c | ||||
| MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o} | ||||
|  |  | |||
|  | @ -14,7 +14,9 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <limits.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "multicall.h" | ||||
| 
 | ||||
| const char *avail_counters[] = { | ||||
|  | @ -30,9 +32,69 @@ const char *avail_counters[] = { | |||
| 
 | ||||
| size_t avail_counters_count = ARRAY_SIZE(avail_counters); | ||||
| 
 | ||||
| const char * | ||||
| char * | ||||
| read_counter(const char *interface, const char *counter) | ||||
| { | ||||
| 	errno = ENOSYS; | ||||
| 	return NULL; | ||||
| 	FILE *fp; | ||||
| 	const char *path; | ||||
| 	char full_path[PATH_MAX]; | ||||
| 	char buffer[1024]; | ||||
| 	size_t in_count; | ||||
| 
 | ||||
| 	errno = 0; | ||||
| 
 | ||||
| 	if (strcasecmp(counter, "rx.octets") == 0) | ||||
| 	{ | ||||
| 		path = "rx_bytes"; | ||||
| 	} else if (strcasecmp(counter, "rx.packets") == 0) { | ||||
| 		path = "rx_packets"; | ||||
| 	} else if (strcasecmp(counter, "rx.discard") == 0) { | ||||
| 		path = "rx_dropped"; | ||||
| 	} else if (strcasecmp(counter, "rx.errors") == 0) { | ||||
| 		path = "rx_errors"; | ||||
| 	} else if (strcasecmp(counter, "tx.octets") == 0) { | ||||
| 		path = "tx_bytes"; | ||||
| 	} else if (strcasecmp(counter, "tx.packets") == 0) { | ||||
| 		path = "tx_packets"; | ||||
| 	} else if (strcasecmp(counter, "tx.discard") == 0) { | ||||
| 		path = "tx_dropped"; | ||||
| 	} else if (strcasecmp(counter, "tx.errors") == 0) { | ||||
| 		path = "tx_errors"; | ||||
| 	} else { | ||||
| 		errno = ENOSYS; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (snprintf(full_path, PATH_MAX, "/sys/class/net/%s/statistics/%s", interface, path) > PATH_MAX) | ||||
| 	{ | ||||
| 		errno = ENOMEM; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	fp = fopen(full_path, "r"); | ||||
| 	if (!fp) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	in_count = fread(buffer, 1, sizeof(buffer), fp); | ||||
| 
 | ||||
| 	if (in_count == sizeof(buffer)) | ||||
| 	{ | ||||
| 		errno = ENOMEM; | ||||
| 		fclose(fp); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ferror(fp)) | ||||
| 	{ | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	fclose(fp); | ||||
| 
 | ||||
| 	/* take away the \n, we add our own */ | ||||
| 	buffer[in_count - 1] = '\0'; | ||||
| 
 | ||||
| 	return strdup(buffer); | ||||
| } | ||||
|  |  | |||
|  | @ -37,16 +37,44 @@ counter_is_valid(const char *candidate) | |||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| print_counter(const char *iface, const char *name, const char *value) | ||||
| { | ||||
| 	fprintf(stdout, "%s: %s\n", name, value); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| print_all_counters(const char *iface) | ||||
| { | ||||
| 	int code = EXIT_SUCCESS; | ||||
| 	const char *res; | ||||
| 
 | ||||
| 	for (int i = 0; i < avail_counters_count; i++) { | ||||
| 		const char *ctr = avail_counters[i]; | ||||
| 
 | ||||
| 		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; | ||||
| 		} else { | ||||
| 			print_counter(iface, ctr, res); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return code; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| ifstats_list_counters(int short_opt, const struct if_option *opt, | ||||
| 		const char *opt_arg, const struct if_applet *applet) | ||||
| ifctrstat_list_counters(int short_opt, const struct if_option *opt, const char *opt_arg, const struct if_applet *applet) | ||||
| { | ||||
| 	(void) short_opt; | ||||
| 	(void) opt; | ||||
| 	(void) opt_arg; | ||||
| 	(void) applet; | ||||
| 
 | ||||
| 	for (int i = 0; i < avail_counters_count; i++) { | ||||
| 	for (int i = 0; i < avail_counters_count; i++) | ||||
| 	{ | ||||
| 		fprintf(stdout, "%s\n", avail_counters[i]); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -54,27 +82,31 @@ ifstats_list_counters(int short_opt, const struct if_option *opt, | |||
| } | ||||
| 
 | ||||
| int | ||||
| ifstats_main(int argc, char *argv[]) | ||||
| ifctrstat_main(int argc, char *argv[]) | ||||
| { | ||||
| 	if (optind >= argc) | ||||
| 		generic_usage(self_applet, EXIT_FAILURE); | ||||
| 
 | ||||
| 	int idx = optind; | ||||
| 	if (argc - idx < 2) | ||||
| 	if (argc - idx == 0) | ||||
| 	{ | ||||
| 		fprintf(stderr, "%s: interface and counter(s) required\n", | ||||
| 		fprintf(stderr, "%s: interface required\n", | ||||
| 			argv0); | ||||
| 		return EXIT_FAILURE; | ||||
| 	} | ||||
| 
 | ||||
| 	const char *iface = argv[idx++]; | ||||
| 
 | ||||
| 	if (argc - idx == 0) | ||||
| 	{ | ||||
| 		return print_all_counters(iface); | ||||
| 	} | ||||
| 
 | ||||
| 	for (; idx < argc; idx++) | ||||
| 	{ | ||||
| 		if (!counter_is_valid(argv[idx])) | ||||
| 		{ | ||||
| 			fprintf(stderr, "%s: counter %s is not valid or not " | ||||
| 					"available\n", argv0, argv[idx]); | ||||
| 			fprintf(stderr, "%s: counter %s is not valid or not available\n", argv0, argv[idx]); | ||||
| 			return EXIT_FAILURE; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -82,18 +114,18 @@ ifstats_main(int argc, char *argv[]) | |||
| 		const char *res = read_counter(iface, argv[idx]); | ||||
| 		if (!res) | ||||
| 		{ | ||||
| 			fprintf(stderr, "%s: could not determine value of " | ||||
| 					"%s for interface %s: %s\n", argv0, | ||||
| 					argv[idx], iface, strerror(errno)); | ||||
| 			fprintf(stderr, "%s: could not determine value of %s for interface %s: %s\n", argv0, argv[idx], iface, strerror(errno)); | ||||
| 			return EXIT_FAILURE; | ||||
| 		} | ||||
| 
 | ||||
| 		print_counter(iface, argv[idx], res); | ||||
| 	} | ||||
| 
 | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| static struct if_option local_options[] = { | ||||
| 	{'L', "list", NULL, "List available counters", false, ifstats_list_counters} | ||||
| 	{'L', "list", NULL, "List available counters", false, ifctrstat_list_counters} | ||||
| }; | ||||
| 
 | ||||
| static struct if_option_group local_option_group = { | ||||
|  | @ -105,7 +137,7 @@ static struct if_option_group local_option_group = { | |||
| struct if_applet ifctrstat_applet = { | ||||
| 	.name = "ifctrstat", | ||||
| 	.desc = "Display statistics about an interface", | ||||
| 	.main = ifstats_main, | ||||
| 	.main = ifctrstat_main, | ||||
| 	.usage = "ifctrstat [options] <interface> <counter>\n  ifctrstat [options] --list\n", | ||||
| 	.groups = { &global_option_group, &local_option_group, NULL } | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue