brctl: make "show" command retrieve data from /sys

ioctl interface is obsolete and has no 32/64 compat shim,
making "brctl show" fail for 32-bit userspace and 64-bit kernel.

function                                             old     new   delta
show_bridge                                            -     310    +310
read_file                                              -      64     +64
if_indextoname                                       117       -    -117
brctl_main                                          1183     885    -298
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 0/1 up/down: 374/-415)          Total: -41 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2019-04-12 18:52:31 +02:00
parent e2026381be
commit c5150e9ce7

View File

@ -67,6 +67,7 @@
//usage: )
#include "libbb.h"
#include "common_bufsiz.h"
#include <linux/sockios.h>
#include <net/if.h>
@ -198,6 +199,69 @@ static void arm_ioctl(unsigned long *args,
}
#endif
#define filedata bb_common_bufsiz1
static int read_file(const char *name)
{
int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1);
if (n < 0) {
filedata[0] = '\0';
} else {
filedata[n] = '\0';
if (n != 0 && filedata[n - 1] == '\n')
filedata[--n] = '\0';
}
return n;
}
/* NB: we are in /sys/class/net
*/
static int show_bridge(const char *name, int need_hdr)
{
// Output:
//bridge name bridge id STP enabled interfaces
//br0 8000.000000000000 no eth0
char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32];
int tabs;
DIR *ifaces;
struct dirent *ent;
char *sfx;
sfx = pathbuf + sprintf(pathbuf, "%s/bridge/", name);
strcpy(sfx, "bridge_id");
if (read_file(pathbuf) < 0)
return -1; /* this iface is not a bridge */
if (need_hdr)
puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
printf("%s\t\t", name);
printf("%s\t", filedata);
strcpy(sfx, "stp_state");
read_file(pathbuf);
if (LONE_CHAR(filedata, '0'))
strcpy(filedata, "no");
else
if (LONE_CHAR(filedata, '1'))
strcpy(filedata, "yes");
printf(filedata);
strcpy(sfx, "brif");
tabs = 0;
ifaces = opendir(pathbuf);
if (ifaces) {
while ((ent = readdir(ifaces)) != NULL) {
if (tabs)
printf("\t\t\t\t\t");
else
tabs = 1;
printf("\t\t%s\n", ent->d_name);
}
closedir(ifaces);
}
if (!tabs) /* bridge has no interfaces */
bb_putchar('\n');
return 0;
}
int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int brctl_main(int argc UNUSED_PARAM, char **argv)
@ -226,6 +290,13 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
char *br, *brif;
argv++;
if (!*argv) {
/* bare "brctl" shows --help */
bb_show_usage();
}
xchdir("/sys/class/net");
while (*argv) {
#if ENABLE_FEATURE_BRCTL_FANCY
int ifidx[MAX_PORTS];
@ -237,68 +308,50 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
if (key == -1) /* no match found in keywords array, bail out. */
bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
argv++;
fd = xsocket(AF_INET, SOCK_STREAM, 0);
#if ENABLE_FEATURE_BRCTL_SHOW
if (key == ARG_show) { /* show */
char buf[IFNAMSIZ];
int bridx[MAX_PORTS];
int i, num;
arm_ioctl(args, BRCTL_GET_BRIDGES,
(unsigned long) bridx, MAX_PORTS);
num = xioctl(fd, SIOCGIFBR, args);
puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
for (i = 0; i < num; i++) {
int j, tabs;
struct __bridge_info bi;
unsigned char *x;
DIR *net;
struct dirent *ent;
int need_hdr = 1;
int exitcode = EXIT_SUCCESS;
if (!if_indextoname(bridx[i], buf))
bb_perror_msg_and_die("can't get bridge name for index %d", i);
strncpy_IFNAMSIZ(ifr.ifr_name, buf);
arm_ioctl(args, BRCTL_GET_BRIDGE_INFO,
(unsigned long) &bi, 0);
xioctl(fd, SIOCDEVPRIVATE, &ifr);
printf("%s\t\t", buf);
/* print bridge id */
x = (unsigned char *) &bi.bridge_id;
for (j = 0; j < 8; j++) {
printf("%02x", x[j]);
if (j == 1)
bb_putchar('.');
}
printf(bi.stp_enabled ? "\tyes" : "\tno");
/* print interface list */
arm_ioctl(args, BRCTL_GET_PORT_LIST,
(unsigned long) ifidx, MAX_PORTS);
xioctl(fd, SIOCDEVPRIVATE, &ifr);
tabs = 0;
for (j = 0; j < MAX_PORTS; j++) {
if (!ifidx[j])
continue;
if (!if_indextoname(ifidx[j], buf))
bb_perror_msg_and_die("can't get interface name for index %d", j);
if (tabs)
printf("\t\t\t\t\t");
else
tabs = 1;
printf("\t\t%s\n", buf);
}
if (!tabs) /* bridge has no interfaces */
bb_putchar('\n');
if (*argv) {
/* "brctl show BR1 BR2 BR3" */
do {
if (show_bridge(*argv, need_hdr) >= 0) {
need_hdr = 0;
} else {
bb_error_msg("bridge %s does not exist", *argv);
//TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 says this instead:
// "device eth0 is not a bridge"
exitcode = EXIT_FAILURE;
}
} while (*++argv != NULL);
return exitcode;
}
goto done;
/* "brctl show" (if no ifaces, shows nothing, not even header) */
net = xopendir(".");
while ((ent = readdir(net)) != NULL) {
if (DOT_OR_DOTDOT(ent->d_name))
continue; /* . or .. */
if (show_bridge(ent->d_name, need_hdr) >= 0)
need_hdr = 0;
}
closedir(net);
return exitcode;
}
#endif
if (!*argv) /* all but 'show' need at least one argument */
bb_show_usage();
fd = xsocket(AF_INET, SOCK_STREAM, 0);
br = *argv++;
//brctl from bridge-utils 1.6 also still uses ioctl
//for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses
if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
ioctl_or_perror_and_die(fd,
key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
@ -329,6 +382,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
int onoff = index_in_strings(no_yes, *argv);
if (onoff < 0)
bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
//TODO: replace with:
//write "0\n" or "1\n" to /sys/class/net/BR/bridge/stp_state
onoff = (unsigned)onoff / 4;
arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0);
goto fire;
@ -340,6 +395,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */
BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */
};
//TODO: replace with:
//setageing BR N: write "N*100\n" to /sys/class/net/BR/bridge/ageing_time
//setfd BR N: write "N*100\n" to /sys/class/net/BR/bridge/forward_delay
//sethello BR N: write "N*100\n" to /sys/class/net/BR/bridge/hello_time
//setmaxage BR N: write "N*100\n" to /sys/class/net/BR/bridge/max_age
arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0);
goto fire;
}
@ -355,6 +415,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
int port = -1;
unsigned arg1, arg2;
//TODO: replace with:
//setbridgeprio BR N: write "N\n" to /sys/class/net/BR/bridge/priority
//setpathcost BR PORT N: ??
//setportprio BR PORT N: ??
if (key != ARG_setbridgeprio) {
/* get portnum */
unsigned i;