mirror_iproute2/ip/ipmaddr.c
Matteo Croce 8589eb4efd treewide: refactor help messages
Every tool in the iproute2 package have one or more function to show
an help message to the user. Some of these functions print the help
line by line with a series of printf call, e.g. ip/xfrm_state.c does
60 fprintf calls.
If we group all the calls to a single one and just concatenate strings,
we save a lot of libc calls and thus object size. The size difference
of the compiled binaries calculated with bloat-o-meter is:

        ip/ip:
        add/remove: 0/0 grow/shrink: 5/15 up/down: 103/-4796 (-4693)
        Total: Before=672591, After=667898, chg -0.70%
        ip/rtmon:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-54 (-54)
        Total: Before=48879, After=48825, chg -0.11%
        tc/tc:
        add/remove: 0/2 grow/shrink: 31/10 up/down: 882/-6133 (-5251)
        Total: Before=351912, After=346661, chg -1.49%
        bridge/bridge:
        add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-459 (-459)
        Total: Before=70502, After=70043, chg -0.65%
        misc/lnstat:
        add/remove: 0/1 grow/shrink: 1/0 up/down: 48/-486 (-438)
        Total: Before=9960, After=9522, chg -4.40%
        tipc/tipc:
        add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-62 (-44)
        Total: Before=79182, After=79138, chg -0.06%

While at it, indent some strings which were starting at column 0,
and use tabs where possible, to have a consistent style across helps.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
2019-05-20 14:35:07 -07:00

370 lines
7.5 KiB
C

/*
* ipmaddr.c "ip maddress".
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <linux/netdevice.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "json_print.h"
static struct {
char *dev;
int family;
} filter;
static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr,
"Usage: ip maddr [ add | del ] MULTIADDR dev STRING\n"
" ip maddr show [ dev STRING ]\n");
exit(-1);
}
static int parse_hex(char *str, unsigned char *addr, size_t size)
{
int len = 0;
while (*str && (len < 2 * size)) {
int tmp;
if (str[1] == 0)
return -1;
if (sscanf(str, "%02x", &tmp) != 1)
return -1;
addr[len] = tmp;
len++;
str += 2;
}
return len;
}
struct ma_info {
struct ma_info *next;
int index;
int users;
char *features;
char name[IFNAMSIZ];
inet_prefix addr;
};
static void maddr_ins(struct ma_info **lst, struct ma_info *m)
{
struct ma_info *mp;
for (; (mp = *lst) != NULL; lst = &mp->next) {
if (mp->index > m->index)
break;
}
m->next = *lst;
*lst = m;
}
static void read_dev_mcast(struct ma_info **result_p)
{
char buf[256];
FILE *fp = fopen("/proc/net/dev_mcast", "r");
if (!fp)
return;
while (fgets(buf, sizeof(buf), fp)) {
char hexa[256];
struct ma_info m = { .addr.family = AF_PACKET };
int len;
int st;
sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st,
hexa);
if (filter.dev && strcmp(filter.dev, m.name))
continue;
len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data));
if (len >= 0) {
struct ma_info *ma = malloc(sizeof(m));
memcpy(ma, &m, sizeof(m));
ma->addr.bytelen = len;
ma->addr.bitlen = len<<3;
if (st)
ma->features = "static";
maddr_ins(result_p, ma);
}
}
fclose(fp);
}
static void read_igmp(struct ma_info **result_p)
{
struct ma_info m = {
.addr.family = AF_INET,
.addr.bitlen = 32,
.addr.bytelen = 4,
};
char buf[256];
FILE *fp = fopen("/proc/net/igmp", "r");
if (!fp)
return;
if (!fgets(buf, sizeof(buf), fp)) {
fclose(fp);
return;
}
while (fgets(buf, sizeof(buf), fp)) {
struct ma_info *ma;
if (buf[0] != '\t') {
size_t len;
sscanf(buf, "%d%s", &m.index, m.name);
len = strlen(m.name);
if (m.name[len - 1] == ':')
m.name[len - 1] = '\0';
continue;
}
if (filter.dev && strcmp(filter.dev, m.name))
continue;
sscanf(buf, "%08x%d", (__u32 *)&m.addr.data, &m.users);
ma = malloc(sizeof(m));
memcpy(ma, &m, sizeof(m));
maddr_ins(result_p, ma);
}
fclose(fp);
}
static void read_igmp6(struct ma_info **result_p)
{
char buf[256];
FILE *fp = fopen("/proc/net/igmp6", "r");
if (!fp)
return;
while (fgets(buf, sizeof(buf), fp)) {
char hexa[256];
struct ma_info m = { .addr.family = AF_INET6 };
int len;
sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users);
if (filter.dev && strcmp(filter.dev, m.name))
continue;
len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data));
if (len >= 0) {
struct ma_info *ma = malloc(sizeof(m));
memcpy(ma, &m, sizeof(m));
ma->addr.bytelen = len;
ma->addr.bitlen = len<<3;
maddr_ins(result_p, ma);
}
}
fclose(fp);
}
static void print_maddr(FILE *fp, struct ma_info *list)
{
print_string(PRINT_FP, NULL, "\t", NULL);
open_json_object(NULL);
if (list->addr.family == AF_PACKET) {
SPRINT_BUF(b1);
print_string(PRINT_FP, NULL, "link ", NULL);
print_color_string(PRINT_ANY, COLOR_MAC, "link", "%s",
ll_addr_n2a((void *)list->addr.data, list->addr.bytelen,
0, b1, sizeof(b1)));
} else {
print_string(PRINT_ANY, "family", "%-5s ",
family_name(list->addr.family));
print_color_string(PRINT_ANY, ifa_family_color(list->addr.family),
"address", "%s",
format_host(list->addr.family,
-1, list->addr.data));
}
if (list->users != 1)
print_uint(PRINT_ANY, "users", " users %u", list->users);
if (list->features)
print_string(PRINT_ANY, "features", " %s", list->features);
print_string(PRINT_FP, NULL, "\n", NULL);
close_json_object();
}
static void print_mlist(FILE *fp, struct ma_info *list)
{
int cur_index = 0;
new_json_obj(json);
for (; list; list = list->next) {
if (list->index != cur_index || oneline) {
if (cur_index) {
close_json_array(PRINT_JSON, NULL);
close_json_object();
}
open_json_object(NULL);
print_uint(PRINT_ANY, "ifindex", "%d:", list->index);
print_color_string(PRINT_ANY, COLOR_IFNAME,
"ifname", "\t%s", list->name);
print_nl();
cur_index = list->index;
open_json_array(PRINT_JSON, "maddr");
}
print_maddr(fp, list);
}
if (cur_index) {
close_json_array(PRINT_JSON, NULL);
close_json_object();
}
delete_json_obj();
}
static int multiaddr_list(int argc, char **argv)
{
struct ma_info *list = NULL;
if (!filter.family)
filter.family = preferred_family;
while (argc > 0) {
if (1) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
} else if (matches(*argv, "help") == 0)
usage();
if (filter.dev)
duparg2("dev", *argv);
filter.dev = *argv;
}
argv++; argc--;
}
if (!filter.family || filter.family == AF_PACKET)
read_dev_mcast(&list);
if (!filter.family || filter.family == AF_INET)
read_igmp(&list);
if (!filter.family || filter.family == AF_INET6)
read_igmp6(&list);
print_mlist(stdout, list);
return 0;
}
static int multiaddr_modify(int cmd, int argc, char **argv)
{
struct ifreq ifr = {};
int family;
int fd;
if (cmd == RTM_NEWADDR)
cmd = SIOCADDMULTI;
else
cmd = SIOCDELMULTI;
while (argc > 0) {
if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
if (ifr.ifr_name[0])
duparg("dev", *argv);
if (get_ifname(ifr.ifr_name, *argv))
invarg("\"dev\" not a valid ifname", *argv);
} else {
if (matches(*argv, "address") == 0) {
NEXT_ARG();
}
if (matches(*argv, "help") == 0)
usage();
if (ifr.ifr_hwaddr.sa_data[0])
duparg("address", *argv);
if (ll_addr_a2n(ifr.ifr_hwaddr.sa_data,
14, *argv) < 0) {
fprintf(stderr, "Error: \"%s\" is not a legal ll address.\n", *argv);
exit(1);
}
}
argc--; argv++;
}
if (ifr.ifr_name[0] == 0) {
fprintf(stderr, "Not enough information: \"dev\" is required.\n");
exit(-1);
}
switch (preferred_family) {
case AF_INET6:
case AF_PACKET:
case AF_INET:
family = preferred_family;
break;
default:
family = AF_INET;
}
fd = socket(family, SOCK_DGRAM, 0);
if (fd < 0) {
perror("Cannot create socket");
exit(1);
}
if (ioctl(fd, cmd, (char *)&ifr) != 0) {
perror("ioctl");
exit(1);
}
close(fd);
exit(0);
}
int do_multiaddr(int argc, char **argv)
{
if (argc < 1)
return multiaddr_list(0, NULL);
if (matches(*argv, "add") == 0)
return multiaddr_modify(RTM_NEWADDR, argc-1, argv+1);
if (matches(*argv, "delete") == 0)
return multiaddr_modify(RTM_DELADDR, argc-1, argv+1);
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|| matches(*argv, "lst") == 0)
return multiaddr_list(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
fprintf(stderr, "Command \"%s\" is unknown, try \"ip maddr help\".\n", *argv);
exit(-1);
}