diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2019-04-12 18:52:31 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2019-04-12 18:52:31 +0200 |
commit | c5150e9ce7359db136ae9337b2f007c6f7ec3113 (patch) | |
tree | a09cefd02f4ded1cb6bd1095ec5d1b5896393e6f | |
parent | e2026381bed88e79b6f7657eef8319e60ff83041 (diff) | |
download | busybox-w32-c5150e9ce7359db136ae9337b2f007c6f7ec3113.tar.gz busybox-w32-c5150e9ce7359db136ae9337b2f007c6f7ec3113.tar.bz2 busybox-w32-c5150e9ce7359db136ae9337b2f007c6f7ec3113.zip |
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>
-rw-r--r-- | networking/brctl.c | 163 |
1 files changed, 114 insertions, 49 deletions
diff --git a/networking/brctl.c b/networking/brctl.c index ba4a714f8..706ecfc07 100644 --- a/networking/brctl.c +++ b/networking/brctl.c | |||
@@ -67,6 +67,7 @@ | |||
67 | //usage: ) | 67 | //usage: ) |
68 | 68 | ||
69 | #include "libbb.h" | 69 | #include "libbb.h" |
70 | #include "common_bufsiz.h" | ||
70 | #include <linux/sockios.h> | 71 | #include <linux/sockios.h> |
71 | #include <net/if.h> | 72 | #include <net/if.h> |
72 | 73 | ||
@@ -198,6 +199,69 @@ static void arm_ioctl(unsigned long *args, | |||
198 | } | 199 | } |
199 | #endif | 200 | #endif |
200 | 201 | ||
202 | #define filedata bb_common_bufsiz1 | ||
203 | static int read_file(const char *name) | ||
204 | { | ||
205 | int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1); | ||
206 | if (n < 0) { | ||
207 | filedata[0] = '\0'; | ||
208 | } else { | ||
209 | filedata[n] = '\0'; | ||
210 | if (n != 0 && filedata[n - 1] == '\n') | ||
211 | filedata[--n] = '\0'; | ||
212 | } | ||
213 | return n; | ||
214 | } | ||
215 | |||
216 | /* NB: we are in /sys/class/net | ||
217 | */ | ||
218 | static int show_bridge(const char *name, int need_hdr) | ||
219 | { | ||
220 | // Output: | ||
221 | //bridge name bridge id STP enabled interfaces | ||
222 | //br0 8000.000000000000 no eth0 | ||
223 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; | ||
224 | int tabs; | ||
225 | DIR *ifaces; | ||
226 | struct dirent *ent; | ||
227 | char *sfx; | ||
228 | |||
229 | sfx = pathbuf + sprintf(pathbuf, "%s/bridge/", name); | ||
230 | strcpy(sfx, "bridge_id"); | ||
231 | if (read_file(pathbuf) < 0) | ||
232 | return -1; /* this iface is not a bridge */ | ||
233 | |||
234 | if (need_hdr) | ||
235 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); | ||
236 | printf("%s\t\t", name); | ||
237 | printf("%s\t", filedata); | ||
238 | |||
239 | strcpy(sfx, "stp_state"); | ||
240 | read_file(pathbuf); | ||
241 | if (LONE_CHAR(filedata, '0')) | ||
242 | strcpy(filedata, "no"); | ||
243 | else | ||
244 | if (LONE_CHAR(filedata, '1')) | ||
245 | strcpy(filedata, "yes"); | ||
246 | printf(filedata); | ||
247 | |||
248 | strcpy(sfx, "brif"); | ||
249 | tabs = 0; | ||
250 | ifaces = opendir(pathbuf); | ||
251 | if (ifaces) { | ||
252 | while ((ent = readdir(ifaces)) != NULL) { | ||
253 | if (tabs) | ||
254 | printf("\t\t\t\t\t"); | ||
255 | else | ||
256 | tabs = 1; | ||
257 | printf("\t\t%s\n", ent->d_name); | ||
258 | } | ||
259 | closedir(ifaces); | ||
260 | } | ||
261 | if (!tabs) /* bridge has no interfaces */ | ||
262 | bb_putchar('\n'); | ||
263 | return 0; | ||
264 | } | ||
201 | 265 | ||
202 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 266 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
203 | int brctl_main(int argc UNUSED_PARAM, char **argv) | 267 | int brctl_main(int argc UNUSED_PARAM, char **argv) |
@@ -226,6 +290,13 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
226 | char *br, *brif; | 290 | char *br, *brif; |
227 | 291 | ||
228 | argv++; | 292 | argv++; |
293 | if (!*argv) { | ||
294 | /* bare "brctl" shows --help */ | ||
295 | bb_show_usage(); | ||
296 | } | ||
297 | |||
298 | xchdir("/sys/class/net"); | ||
299 | |||
229 | while (*argv) { | 300 | while (*argv) { |
230 | #if ENABLE_FEATURE_BRCTL_FANCY | 301 | #if ENABLE_FEATURE_BRCTL_FANCY |
231 | int ifidx[MAX_PORTS]; | 302 | int ifidx[MAX_PORTS]; |
@@ -237,68 +308,50 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
237 | if (key == -1) /* no match found in keywords array, bail out. */ | 308 | if (key == -1) /* no match found in keywords array, bail out. */ |
238 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); | 309 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
239 | argv++; | 310 | argv++; |
240 | fd = xsocket(AF_INET, SOCK_STREAM, 0); | ||
241 | 311 | ||
242 | #if ENABLE_FEATURE_BRCTL_SHOW | 312 | #if ENABLE_FEATURE_BRCTL_SHOW |
243 | if (key == ARG_show) { /* show */ | 313 | if (key == ARG_show) { /* show */ |
244 | char buf[IFNAMSIZ]; | 314 | DIR *net; |
245 | int bridx[MAX_PORTS]; | 315 | struct dirent *ent; |
246 | int i, num; | 316 | int need_hdr = 1; |
247 | arm_ioctl(args, BRCTL_GET_BRIDGES, | 317 | int exitcode = EXIT_SUCCESS; |
248 | (unsigned long) bridx, MAX_PORTS); | 318 | |
249 | num = xioctl(fd, SIOCGIFBR, args); | 319 | if (*argv) { |
250 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); | 320 | /* "brctl show BR1 BR2 BR3" */ |
251 | for (i = 0; i < num; i++) { | 321 | do { |
252 | int j, tabs; | 322 | if (show_bridge(*argv, need_hdr) >= 0) { |
253 | struct __bridge_info bi; | 323 | need_hdr = 0; |
254 | unsigned char *x; | 324 | } else { |
255 | 325 | bb_error_msg("bridge %s does not exist", *argv); | |
256 | if (!if_indextoname(bridx[i], buf)) | 326 | //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 says this instead: |
257 | bb_perror_msg_and_die("can't get bridge name for index %d", i); | 327 | // "device eth0 is not a bridge" |
258 | strncpy_IFNAMSIZ(ifr.ifr_name, buf); | 328 | exitcode = EXIT_FAILURE; |
259 | 329 | } | |
260 | arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, | 330 | } while (*++argv != NULL); |
261 | (unsigned long) &bi, 0); | 331 | return exitcode; |
262 | xioctl(fd, SIOCDEVPRIVATE, &ifr); | 332 | } |
263 | printf("%s\t\t", buf); | ||
264 | |||
265 | /* print bridge id */ | ||
266 | x = (unsigned char *) &bi.bridge_id; | ||
267 | for (j = 0; j < 8; j++) { | ||
268 | printf("%02x", x[j]); | ||
269 | if (j == 1) | ||
270 | bb_putchar('.'); | ||
271 | } | ||
272 | printf(bi.stp_enabled ? "\tyes" : "\tno"); | ||
273 | 333 | ||
274 | /* print interface list */ | 334 | /* "brctl show" (if no ifaces, shows nothing, not even header) */ |
275 | arm_ioctl(args, BRCTL_GET_PORT_LIST, | 335 | net = xopendir("."); |
276 | (unsigned long) ifidx, MAX_PORTS); | 336 | while ((ent = readdir(net)) != NULL) { |
277 | xioctl(fd, SIOCDEVPRIVATE, &ifr); | 337 | if (DOT_OR_DOTDOT(ent->d_name)) |
278 | tabs = 0; | 338 | continue; /* . or .. */ |
279 | for (j = 0; j < MAX_PORTS; j++) { | 339 | if (show_bridge(ent->d_name, need_hdr) >= 0) |
280 | if (!ifidx[j]) | 340 | need_hdr = 0; |
281 | continue; | ||
282 | if (!if_indextoname(ifidx[j], buf)) | ||
283 | bb_perror_msg_and_die("can't get interface name for index %d", j); | ||
284 | if (tabs) | ||
285 | printf("\t\t\t\t\t"); | ||
286 | else | ||
287 | tabs = 1; | ||
288 | printf("\t\t%s\n", buf); | ||
289 | } | ||
290 | if (!tabs) /* bridge has no interfaces */ | ||
291 | bb_putchar('\n'); | ||
292 | } | 341 | } |
293 | goto done; | 342 | closedir(net); |
343 | return exitcode; | ||
294 | } | 344 | } |
295 | #endif | 345 | #endif |
296 | 346 | ||
297 | if (!*argv) /* all but 'show' need at least one argument */ | 347 | if (!*argv) /* all but 'show' need at least one argument */ |
298 | bb_show_usage(); | 348 | bb_show_usage(); |
299 | 349 | ||
350 | fd = xsocket(AF_INET, SOCK_STREAM, 0); | ||
300 | br = *argv++; | 351 | br = *argv++; |
301 | 352 | ||
353 | //brctl from bridge-utils 1.6 also still uses ioctl | ||
354 | //for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses | ||
302 | if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ | 355 | if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */ |
303 | ioctl_or_perror_and_die(fd, | 356 | ioctl_or_perror_and_die(fd, |
304 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, | 357 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, |
@@ -329,6 +382,8 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
329 | int onoff = index_in_strings(no_yes, *argv); | 382 | int onoff = index_in_strings(no_yes, *argv); |
330 | if (onoff < 0) | 383 | if (onoff < 0) |
331 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); | 384 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
385 | //TODO: replace with: | ||
386 | //write "0\n" or "1\n" to /sys/class/net/BR/bridge/stp_state | ||
332 | onoff = (unsigned)onoff / 4; | 387 | onoff = (unsigned)onoff / 4; |
333 | arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0); | 388 | arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0); |
334 | goto fire; | 389 | goto fire; |
@@ -340,6 +395,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
340 | BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */ | 395 | BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */ |
341 | BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */ | 396 | BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */ |
342 | }; | 397 | }; |
398 | //TODO: replace with: | ||
399 | //setageing BR N: write "N*100\n" to /sys/class/net/BR/bridge/ageing_time | ||
400 | //setfd BR N: write "N*100\n" to /sys/class/net/BR/bridge/forward_delay | ||
401 | //sethello BR N: write "N*100\n" to /sys/class/net/BR/bridge/hello_time | ||
402 | //setmaxage BR N: write "N*100\n" to /sys/class/net/BR/bridge/max_age | ||
343 | arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0); | 403 | arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0); |
344 | goto fire; | 404 | goto fire; |
345 | } | 405 | } |
@@ -355,6 +415,11 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
355 | int port = -1; | 415 | int port = -1; |
356 | unsigned arg1, arg2; | 416 | unsigned arg1, arg2; |
357 | 417 | ||
418 | //TODO: replace with: | ||
419 | //setbridgeprio BR N: write "N\n" to /sys/class/net/BR/bridge/priority | ||
420 | //setpathcost BR PORT N: ?? | ||
421 | //setportprio BR PORT N: ?? | ||
422 | |||
358 | if (key != ARG_setbridgeprio) { | 423 | if (key != ARG_setbridgeprio) { |
359 | /* get portnum */ | 424 | /* get portnum */ |
360 | unsigned i; | 425 | unsigned i; |