libiproute: audit callgraph, shortcut error paths into die() functions.

Kill a few statics, made other globals smaller:
oneline is smallint, _SL_ is char

function                                             old     new   delta
print_tunnel                                         693     731     +38
print_route                                         1775    1777      +2
print_addrinfo                                      1495    1497      +2
ipaddr_list_or_flush                                2826    2828      +2
oneline                                                4       1      -3
_SL_                                                   4       1      -3
ipaddr_modify                                       1476    1472      -4
parse_address                                        124     119      -5
ip_parse_common_args                                 429     423      -6
on_off                                                53      46      -7
do_del_ioctl                                         113     106      -7
do_add_ioctl                                         120     113      -7
do_show                                              864     856      -8
iprule_list                                          157     148      -9
do_iptunnel                                          310     299     -11
do_add                                               143     126     -17
get_ctl_fd                                            95      76     -19
set_address                                          108      84     -24
ip_main                                              351     323     -28
static.ifr                                            32       -     -32
parse_args                                          1992    1949     -43
iproute_list_or_flush                               1673    1582     -91
do_iplink                                           1583    1485     -98
filter                                               280       -    -280
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 4/18 up/down: 44/-702)         Total: -658 bytes
This commit is contained in:
Denis Vlasenko 2007-04-07 01:14:45 +00:00
parent fbd2918f5c
commit 540a2a1f3b
11 changed files with 247 additions and 319 deletions

View File

@ -20,31 +20,28 @@
int ip_main(int argc, char **argv); int ip_main(int argc, char **argv);
int ip_main(int argc, char **argv) int ip_main(int argc, char **argv)
{ {
int ret = EXIT_FAILURE;
ip_parse_common_args(&argc, &argv); ip_parse_common_args(&argc, &argv);
if (argc > 1) { if (argc <= 1)
if (ENABLE_FEATURE_IP_ADDRESS && matches(argv[1], "address") == 0) {
ret = do_ipaddr(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_ROUTE && matches(argv[1], "route") == 0) {
ret = do_iproute(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_LINK && matches(argv[1], "link") == 0) {
ret = do_iplink(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_TUNNEL
&& (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0)
) {
ret = do_iptunnel(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_RULE && matches(argv[1], "rule") == 0) {
ret = do_iprule(argc-2, argv+2);
}
}
if (ret) {
bb_show_usage(); bb_show_usage();
if (ENABLE_FEATURE_IP_ADDRESS && matches(argv[1], "address") == 0) {
return do_ipaddr(argc-2, argv+2);
} }
return EXIT_SUCCESS; if (ENABLE_FEATURE_IP_ROUTE && matches(argv[1], "route") == 0) {
return do_iproute(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_LINK && matches(argv[1], "link") == 0) {
return do_iplink(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_TUNNEL
&& (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0)
) {
return do_iptunnel(argc-2, argv+2);
}
if (ENABLE_FEATURE_IP_RULE && matches(argv[1], "rule") == 0) {
return do_iprule(argc-2, argv+2);
}
bb_show_usage();
} }

View File

@ -13,16 +13,13 @@
#include <linux/if_link.h> #include <linux/if_link.h>
#endif #endif
extern int preferred_family;
//FIXME! Appears in two .h files!
extern const char * _SL_;
extern void ip_parse_common_args(int *argcp, char ***argvp); extern void ip_parse_common_args(int *argcp, char ***argvp);
extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
extern int ipaddr_list_or_flush(int argc, char **argv, int flush); extern int ipaddr_list_or_flush(int argc, char **argv, int flush);
extern int iproute_monitor(int argc, char **argv); extern int iproute_monitor(int argc, char **argv);
extern void iplink_usage(void) ATTRIBUTE_NORETURN; extern void iplink_usage(void) ATTRIBUTE_NORETURN;
extern void ipneigh_reset_filter(void); extern void ipneigh_reset_filter(void);
extern int do_ipaddr(int argc, char **argv); extern int do_ipaddr(int argc, char **argv);
extern int do_iproute(int argc, char **argv); extern int do_iproute(int argc, char **argv);
extern int do_iprule(int argc, char **argv); extern int do_iprule(int argc, char **argv);

View File

@ -23,8 +23,8 @@
int preferred_family = AF_UNSPEC; int preferred_family = AF_UNSPEC;
int oneline = 0; smallint oneline;
const char * _SL_ = NULL; char _SL_;
void ip_parse_common_args(int *argcp, char ***argvp) void ip_parse_common_args(int *argcp, char ***argvp)
{ {
@ -73,7 +73,7 @@ void ip_parse_common_args(int *argcp, char ***argvp)
argc--; argc--;
argv++; argv++;
} }
_SL_ = oneline ? "\\" : "\n" ; _SL_ = oneline ? '\\' : '\n' ;
*argcp = argc; *argcp = argc;
*argvp = argv; *argvp = argv;
} }

View File

@ -26,8 +26,7 @@
#include "ip_common.h" #include "ip_common.h"
static struct typedef struct filter_t {
{
int ifindex; int ifindex;
int family; int family;
int oneline; int oneline;
@ -42,7 +41,10 @@ static struct
int flushp; int flushp;
int flushe; int flushe;
struct rtnl_handle *rth; struct rtnl_handle *rth;
} filter; } filter_t;
#define filter (*(filter_t*)&bb_common_bufsiz1)
static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
{ {
@ -88,7 +90,7 @@ static void print_queuelen(char *name)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
perror("SIOCGIFXQLEN"); bb_perror_msg("SIOCGIFXQLEN");
close(s); close(s);
return; return;
} }
@ -125,10 +127,12 @@ static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
bb_error_msg("nil ifname"); bb_error_msg("nil ifname");
return -1; return -1;
} }
if (filter.label && if (filter.label
(!filter.family || filter.family == AF_PACKET) && && (!filter.family || filter.family == AF_PACKET)
fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)
) {
return 0; return 0;
}
if (n->nlmsg_type == RTM_DELLINK) if (n->nlmsg_type == RTM_DELLINK)
fprintf(fp, "Deleted "); fprintf(fp, "Deleted ");
@ -166,8 +170,7 @@ static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
if (!filter.family || filter.family == AF_PACKET) { if (!filter.family || filter.family == AF_PACKET) {
SPRINT_BUF(b1); SPRINT_BUF(b1);
fprintf(fp, "%s", _SL_); fprintf(fp, "%c link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
if (tb[IFLA_ADDRESS]) { if (tb[IFLA_ADDRESS]) {
fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
@ -186,7 +189,7 @@ static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
b1, sizeof(b1))); b1, sizeof(b1)));
} }
} }
fprintf(fp, "\n"); fputc('\n', fp);
fflush(fp); fflush(fp);
return 0; return 0;
} }
@ -194,7 +197,7 @@ static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
static int flush_update(void) static int flush_update(void)
{ {
if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
perror("Failed to send flush request\n"); bb_perror_msg("failed to send flush request");
return -1; return -1;
} }
filter.flushp = 0; filter.flushp = 0;
@ -341,7 +344,7 @@ static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
if (rta_tb[IFA_CACHEINFO]) { if (rta_tb[IFA_CACHEINFO]) {
struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
char buf[128]; char buf[128];
fprintf(fp, "%s", _SL_); fputc(_SL_, fp);
if (ci->ifa_valid == 0xFFFFFFFFU) if (ci->ifa_valid == 0xFFFFFFFFU)
sprintf(buf, "valid_lft forever"); sprintf(buf, "valid_lft forever");
else else
@ -352,7 +355,7 @@ static int print_addrinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered); sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
fprintf(fp, " %s", buf); fprintf(fp, " %s", buf);
} }
fprintf(fp, "\n"); fputc('\n', fp);
fflush(fp); fflush(fp);
return 0; return 0;
} }
@ -366,7 +369,7 @@ struct nlmsg_list
static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp) static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
{ {
for ( ;ainfo ; ainfo = ainfo->next) { for (; ainfo; ainfo = ainfo->next) {
struct nlmsghdr *n = &ainfo->h; struct nlmsghdr *n = &ainfo->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n); struct ifaddrmsg *ifa = NLMSG_DATA(n);
@ -412,6 +415,7 @@ static void ipaddr_reset_filter(int _oneline)
filter.oneline = _oneline; filter.oneline = _oneline;
} }
/* Return value becomes exitcode. It's okay to not return at all */
int ipaddr_list_or_flush(int argc, char **argv, int flush) int ipaddr_list_or_flush(int argc, char **argv, int flush)
{ {
static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 }; static const char *const option[] = { "to", "scope", "up", "label", "dev", 0 };
@ -431,12 +435,10 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
if (flush) { if (flush) {
if (argc <= 0) { if (argc <= 0) {
bb_error_msg(bb_msg_requires_arg, "flush"); bb_error_msg_and_die(bb_msg_requires_arg, "flush");
return -1;
} }
if (filter.family == AF_PACKET) { if (filter.family == AF_PACKET) {
bb_error_msg("cannot flush link addresses"); bb_error_msg_and_die("cannot flush link addresses");
return -1;
} }
} }
@ -498,8 +500,7 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
if (filter_dev) { if (filter_dev) {
filter.ifindex = ll_name_to_index(filter_dev); filter.ifindex = ll_name_to_index(filter_dev);
if (filter.ifindex <= 0) { if (filter.ifindex <= 0) {
bb_error_msg("device \"%s\" does not exist", filter_dev); bb_error_msg_and_die("device \"%s\" does not exist", filter_dev);
return -1;
} }
} }
@ -513,20 +514,17 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
for (;;) { for (;;) {
if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
perror("Cannot send dump request"); bb_perror_msg_and_die("cannot send dump request");
exit(1);
} }
filter.flushed = 0; filter.flushed = 0;
if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) { if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
fprintf(stderr, "Flush terminated\n"); bb_error_msg_and_die("flush terminated");
exit(1);
} }
if (filter.flushed == 0) { if (filter.flushed == 0) {
fflush(stdout);
return 0; return 0;
} }
if (flush_update() < 0) if (flush_update() < 0)
exit(1); return 1;
} }
} }
@ -601,16 +599,16 @@ int ipaddr_list_or_flush(int argc, char **argv, int flush)
} }
} }
for (l=linfo; l; l = l->next) { for (l = linfo; l; l = l->next) {
if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) { if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
struct ifinfomsg *ifi = NLMSG_DATA(&l->h); struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
if (filter.family != AF_PACKET) if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi->ifi_index, ainfo, stdout); print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
} }
fflush(stdout); fflush(stdout); /* why? */
} }
exit(0); return 0;
} }
static int default_scope(inet_prefix *lcl) static int default_scope(inet_prefix *lcl)
@ -622,6 +620,7 @@ static int default_scope(inet_prefix *lcl)
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int ipaddr_modify(int cmd, int argc, char **argv) static int ipaddr_modify(int cmd, int argc, char **argv)
{ {
static const char *const option[] = { static const char *const option[] = {
@ -763,8 +762,7 @@ static int ipaddr_modify(int cmd, int argc, char **argv)
inet_prefix brd; inet_prefix brd;
int i; int i;
if (req.ifa.ifa_family != AF_INET) { if (req.ifa.ifa_family != AF_INET) {
bb_error_msg("broadcast can be set only for IPv4 addresses"); bb_error_msg_and_die("broadcast can be set only for IPv4 addresses");
return -1;
} }
brd = peer; brd = peer;
if (brd.bitlen <= 30) { if (brd.bitlen <= 30) {
@ -786,17 +784,18 @@ static int ipaddr_modify(int cmd, int argc, char **argv)
ll_init_map(&rth); ll_init_map(&rth);
if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { req.ifa.ifa_index = ll_name_to_index(d);
bb_error_msg("cannot find device \"%s\"", d); if (req.ifa.ifa_index == 0) {
return -1; bb_error_msg_and_die("cannot find device \"%s\"", d);
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
exit(2); return 2;
exit(0); return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
int do_ipaddr(int argc, char **argv) int do_ipaddr(int argc, char **argv)
{ {
static const char *const commands[] = { static const char *const commands[] = {

View File

@ -22,63 +22,54 @@
#include "utils.h" #include "utils.h"
#include "ip_common.h" #include "ip_common.h"
/* take from linux/sockios.h */ /* taken from linux/sockios.h */
#define SIOCSIFNAME 0x8923 /* set interface name */ #define SIOCSIFNAME 0x8923 /* set interface name */
static int on_off(const char *msg) static void on_off(const char *msg) ATTRIBUTE_NORETURN;
static void on_off(const char *msg)
{ {
bb_error_msg("error: argument of \"%s\" must be \"on\" or \"off\"", msg); bb_error_msg_and_die("error: argument of \"%s\" must be \"on\" or \"off\"", msg);
return -1;
} }
/* Exits on error */
static int get_ctl_fd(void) static int get_ctl_fd(void)
{ {
int s_errno;
int fd; int fd;
fd = socket(PF_INET, SOCK_DGRAM, 0); fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0) if (fd >= 0)
return fd; return fd;
s_errno = errno;
fd = socket(PF_PACKET, SOCK_DGRAM, 0); fd = socket(PF_PACKET, SOCK_DGRAM, 0);
if (fd >= 0) if (fd >= 0)
return fd; return fd;
fd = socket(PF_INET6, SOCK_DGRAM, 0); fd = socket(PF_INET6, SOCK_DGRAM, 0);
if (fd >= 0) if (fd >= 0)
return fd; return fd;
errno = s_errno; bb_perror_msg_and_die("cannot create control socket");
bb_perror_msg("cannot create control socket");
return -1;
} }
static int do_chflags(char *dev, uint32_t flags, uint32_t mask) /* Exits on error */
static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd; int fd;
int err;
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
fd = get_ctl_fd(); fd = get_ctl_fd();
if (fd < 0) if (ioctl(fd, SIOCGIFFLAGS, &ifr)) {
return -1; bb_perror_msg_and_die("SIOCGIFFLAGS");
err = ioctl(fd, SIOCGIFFLAGS, &ifr);
if (err) {
bb_perror_msg("SIOCGIFFLAGS");
close(fd);
return -1;
} }
if ((ifr.ifr_flags^flags)&mask) { if ((ifr.ifr_flags ^ flags) & mask) {
ifr.ifr_flags &= ~mask; ifr.ifr_flags &= ~mask;
ifr.ifr_flags |= mask&flags; ifr.ifr_flags |= mask & flags;
err = ioctl(fd, SIOCSIFFLAGS, &ifr); if (ioctl(fd, SIOCSIFFLAGS, &ifr))
if (err) bb_perror_msg_and_die("SIOCSIFFLAGS");
bb_perror_msg("SIOCSIFFLAGS");
} }
close(fd); close(fd);
return err;
} }
static int do_changename(char *dev, char *newdev) /* Exits on error */
static void do_changename(char *dev, char *newdev)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd; int fd;
@ -87,62 +78,46 @@ static int do_changename(char *dev, char *newdev)
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname)); strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
fd = get_ctl_fd(); fd = get_ctl_fd();
if (fd < 0)
return -1;
err = ioctl(fd, SIOCSIFNAME, &ifr); err = ioctl(fd, SIOCSIFNAME, &ifr);
if (err) { if (err) {
bb_perror_msg("SIOCSIFNAME"); bb_perror_msg_and_die("SIOCSIFNAME");
close(fd);
return -1;
} }
close(fd); close(fd);
return err;
} }
static int set_qlen(char *dev, int qlen) /* Exits on error */
static void set_qlen(char *dev, int qlen)
{ {
struct ifreq ifr; struct ifreq ifr;
int s; int s;
s = get_ctl_fd(); s = get_ctl_fd();
if (s < 0)
return -1;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
ifr.ifr_qlen = qlen; ifr.ifr_qlen = qlen;
if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
bb_perror_msg("SIOCSIFXQLEN"); bb_perror_msg_and_die("SIOCSIFXQLEN");
close(s);
return -1;
} }
close(s); close(s);
return 0;
} }
static int set_mtu(char *dev, int mtu) /* Exits on error */
static void set_mtu(char *dev, int mtu)
{ {
struct ifreq ifr; struct ifreq ifr;
int s; int s;
s = get_ctl_fd(); s = get_ctl_fd();
if (s < 0)
return -1;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
ifr.ifr_mtu = mtu; ifr.ifr_mtu = mtu;
if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
bb_perror_msg("SIOCSIFMTU"); bb_perror_msg_and_die("SIOCSIFMTU");
close(s);
return -1;
} }
close(s); close(s);
return 0;
} }
/* Exits on error */
static int get_address(char *dev, int *htype) static int get_address(char *dev, int *htype)
{ {
struct ifreq ifr; struct ifreq ifr;
@ -152,16 +127,13 @@ static int get_address(char *dev, int *htype)
s = socket(PF_PACKET, SOCK_DGRAM, 0); s = socket(PF_PACKET, SOCK_DGRAM, 0);
if (s < 0) { if (s < 0) {
bb_perror_msg("socket(PF_PACKET)"); bb_perror_msg_and_die("socket(PF_PACKET)");
return -1;
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
bb_perror_msg("SIOCGIFINDEX"); bb_perror_msg_and_die("SIOCGIFINDEX");
close(s);
return -1;
} }
memset(&me, 0, sizeof(me)); memset(&me, 0, sizeof(me));
@ -169,23 +141,20 @@ static int get_address(char *dev, int *htype)
me.sll_ifindex = ifr.ifr_ifindex; me.sll_ifindex = ifr.ifr_ifindex;
me.sll_protocol = htons(ETH_P_LOOP); me.sll_protocol = htons(ETH_P_LOOP);
if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
bb_perror_msg("bind"); bb_perror_msg_and_die("bind");
close(s);
return -1;
} }
alen = sizeof(me); alen = sizeof(me);
if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
bb_perror_msg("getsockname"); bb_perror_msg_and_die("getsockname");
close(s);
return -1;
} }
close(s); close(s);
*htype = me.sll_hatype; *htype = me.sll_hatype;
return me.sll_halen; return me.sll_halen;
} }
static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) /* Exits on error */
static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
{ {
int alen; int alen;
@ -194,31 +163,26 @@ static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifr
ifr->ifr_hwaddr.sa_family = hatype; ifr->ifr_hwaddr.sa_family = hatype;
alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla); alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);
if (alen < 0) if (alen < 0)
return -1; exit(1);
if (alen != halen) { if (alen != halen) {
bb_error_msg("wrong address (%s) length: expected %d bytes", lla, halen); bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
return -1;
} }
return 0;
} }
static int set_address(struct ifreq *ifr, int brd) /* Exits on error */
static void set_address(struct ifreq *ifr, int brd)
{ {
int s; int s;
s = get_ctl_fd(); s = get_ctl_fd();
if (s < 0) if (ioctl(s, brd ? SIOCSIFHWBROADCAST :SIOCSIFHWADDR, ifr) < 0) {
return -1; bb_perror_msg_and_die(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR");
if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
bb_perror_msg(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR");
close(s);
return -1;
} }
close(s); close(s);
return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int do_set(int argc, char **argv) static int do_set(int argc, char **argv)
{ {
char *dev = NULL; char *dev = NULL;
@ -256,7 +220,7 @@ static int do_set(int argc, char **argv)
} else if (strcmp(*argv, "off") == 0) { } else if (strcmp(*argv, "off") == 0) {
flags &= ~IFF_MULTICAST; flags &= ~IFF_MULTICAST;
} else } else
return on_off("multicast"); on_off("multicast");
} else if (strcmp(*argv, "arp") == 0) { } else if (strcmp(*argv, "arp") == 0) {
NEXT_ARG(); NEXT_ARG();
mask |= IFF_NOARP; mask |= IFF_NOARP;
@ -265,7 +229,7 @@ static int do_set(int argc, char **argv)
} else if (strcmp(*argv, "off") == 0) { } else if (strcmp(*argv, "off") == 0) {
flags |= IFF_NOARP; flags |= IFF_NOARP;
} else } else
return on_off("noarp"); on_off("noarp");
} else if (strcmp(*argv, "addr") == 0) { } else if (strcmp(*argv, "addr") == 0) {
NEXT_ARG(); NEXT_ARG();
newaddr = *argv; newaddr = *argv;
@ -277,53 +241,44 @@ static int do_set(int argc, char **argv)
duparg2("dev", *argv); duparg2("dev", *argv);
dev = *argv; dev = *argv;
} }
argc--; argv++; argc--;
argv++;
} }
if (!dev) { if (!dev) {
bb_error_msg(bb_msg_requires_arg, "\"dev\""); bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
exit(-1);
} }
if (newaddr || newbrd) { if (newaddr || newbrd) {
halen = get_address(dev, &htype); halen = get_address(dev, &htype);
if (halen < 0)
return -1;
if (newaddr) { if (newaddr) {
if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) parse_address(dev, htype, halen, newaddr, &ifr0);
return -1;
} }
if (newbrd) { if (newbrd) {
if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) parse_address(dev, htype, halen, newbrd, &ifr1);
return -1;
} }
} }
if (newname && strcmp(dev, newname)) { if (newname && strcmp(dev, newname)) {
if (do_changename(dev, newname) < 0) do_changename(dev, newname);
return -1;
dev = newname; dev = newname;
} }
if (qlen != -1) { if (qlen != -1) {
if (set_qlen(dev, qlen) < 0) set_qlen(dev, qlen);
return -1;
} }
if (mtu != -1) { if (mtu != -1) {
if (set_mtu(dev, mtu) < 0) set_mtu(dev, mtu);
return -1;
} }
if (newaddr || newbrd) { if (newaddr || newbrd) {
if (newbrd) { if (newbrd) {
if (set_address(&ifr1, 1) < 0) set_address(&ifr1, 1);
return -1;
} }
if (newaddr) { if (newaddr) {
if (set_address(&ifr0, 0) < 0) set_address(&ifr0, 0);
return -1;
} }
} }
if (mask) if (mask)
return do_chflags(dev, flags, mask); do_chflags(dev, flags, mask);
return 0; return 0;
} }
@ -333,18 +288,19 @@ static int ipaddr_list_link(int argc, char **argv)
return ipaddr_list_or_flush(argc, argv, 0); return ipaddr_list_or_flush(argc, argv, 0);
} }
/* Return value becomes exitcode. It's okay to not return at all */
int do_iplink(int argc, char **argv) int do_iplink(int argc, char **argv)
{ {
if (argc > 0) { if (argc <= 0)
if (matches(*argv, "set") == 0)
return do_set(argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
} else
return ipaddr_list_link(0, NULL); return ipaddr_list_link(0, NULL);
bb_error_msg("command \"%s\" is unknown", *argv); if (matches(*argv, "set") == 0)
exit(-1); return do_set(argc-1, argv+1);
if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
bb_error_msg_and_die("command \"%s\" is unknown", *argv);
} }

View File

@ -24,8 +24,7 @@
#endif #endif
static struct typedef struct filter_t {
{
int tb; int tb;
int flushed; int flushed;
char *flushb; char *flushb;
@ -45,12 +44,14 @@ static struct
inet_prefix mdst; inet_prefix mdst;
inet_prefix rsrc; inet_prefix rsrc;
inet_prefix msrc; inet_prefix msrc;
} filter; } filter_t;
#define filter (*(filter_t*)&bb_common_bufsiz1)
static int flush_update(void) static int flush_update(void)
{ {
if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
perror("Failed to send flush request\n"); bb_perror_msg("failed to send flush request");
return -1; return -1;
} }
filter.flushp = 0; filter.flushp = 0;
@ -273,7 +274,7 @@ static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
} }
if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
if (r->rtm_flags & RTM_F_CLONED) { if (r->rtm_flags & RTM_F_CLONED) {
fprintf(fp, "%s cache ", _SL_); fprintf(fp, "%c cache ", _SL_);
} }
if (ci->rta_expires) { if (ci->rta_expires) {
fprintf(fp, " expires %dsec", ci->rta_expires / get_hz()); fprintf(fp, " expires %dsec", ci->rta_expires / get_hz());
@ -289,11 +290,12 @@ static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
if (tb[RTA_IIF] && filter.iifmask != -1) { if (tb[RTA_IIF] && filter.iifmask != -1) {
fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
} }
fprintf(fp, "\n"); fputc('\n', fp);
fflush(fp); fflush(fp);
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -302,10 +304,10 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
struct rtmsg r; struct rtmsg r;
char buf[1024]; char buf[1024];
} req; } req;
char mxbuf[256]; char mxbuf[256];
struct rtattr * mxrta = (void*)mxbuf; struct rtattr * mxrta = (void*)mxbuf;
unsigned mxlock = 0; unsigned mxlock = 0;
char *d = NULL; char *d = NULL;
int gw_ok = 0; int gw_ok = 0;
int dst_ok = 0; int dst_ok = 0;
int proto_ok = 0; int proto_ok = 0;
@ -384,8 +386,9 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (strcmp(*argv, "to") == 0) { if (strcmp(*argv, "to") == 0) {
NEXT_ARG(); NEXT_ARG();
} }
if ((**argv < '0' || **argv > '9') && if ((**argv < '0' || **argv > '9')
rtnl_rtntype_a2n(&type, *argv) == 0) { && rtnl_rtntype_a2n(&type, *argv) == 0
) {
NEXT_ARG(); NEXT_ARG();
req.r.rtm_type = type; req.r.rtm_type = type;
type_ok = 1; type_ok = 1;
@ -408,7 +411,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
} }
if (rtnl_open(&rth, 0) < 0) { if (rtnl_open(&rth, 0) < 0) {
exit(1); return 1;
} }
if (d) { if (d) {
@ -419,8 +422,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
if (d) { if (d) {
idx = ll_name_to_index(d); idx = ll_name_to_index(d);
if (idx == 0) { if (idx == 0) {
bb_error_msg("cannot find device \"%s\"", d); bb_error_msg_and_die("cannot find device \"%s\"", d);
return -1;
} }
addattr32(&req.n, sizeof(req), RTA_OIF, idx); addattr32(&req.n, sizeof(req), RTA_OIF, idx);
} }
@ -438,7 +440,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
} }
if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
exit(2); return 2;
} }
return 0; return 0;
@ -467,21 +469,21 @@ static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
} }
static int iproute_flush_cache(void) static void iproute_flush_cache(void)
{ {
static const char fn[] = "/proc/sys/net/ipv4/route/flush"; static const char fn[] = "/proc/sys/net/ipv4/route/flush";
int flush_fd = open(fn, O_WRONLY); int flush_fd = open(fn, O_WRONLY);
if (flush_fd < 0) { if (flush_fd < 0) {
bb_perror_msg("cannot open '%s'", fn); bb_perror_msg("cannot open '%s'", fn);
return -1; return;
} }
if (write(flush_fd, "-1", 2) < 2) { if (write(flush_fd, "-1", 2) < 2) {
bb_perror_msg("cannot flush routing cache"); bb_perror_msg("cannot flush routing cache");
return -1; return;
} }
close(flush_fd); close(flush_fd);
return 0;
} }
static void iproute_reset_filter(void) static void iproute_reset_filter(void)
@ -491,6 +493,7 @@ static void iproute_reset_filter(void)
filter.msrc.bitlen = -1; filter.msrc.bitlen = -1;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int iproute_list_or_flush(int argc, char **argv, int flush) static int iproute_list_or_flush(int argc, char **argv, int flush)
{ {
int do_ipv6 = preferred_family; int do_ipv6 = preferred_family;
@ -501,10 +504,8 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
iproute_reset_filter(); iproute_reset_filter();
filter.tb = RT_TABLE_MAIN; filter.tb = RT_TABLE_MAIN;
if (flush && argc <= 0) { if (flush && argc <= 0)
bb_error_msg(bb_msg_requires_arg, "\"ip route flush\""); bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
return -1;
}
while (argc > 0) { while (argc > 0) {
if (matches(*argv, "protocol") == 0) { if (matches(*argv, "protocol") == 0) {
@ -572,7 +573,8 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
filter.rdst = filter.mdst; filter.rdst = filter.mdst;
} }
} }
argc--; argv++; argc--;
argv++;
} }
if (do_ipv6 == AF_UNSPEC && filter.tb) { if (do_ipv6 == AF_UNSPEC && filter.tb) {
@ -580,7 +582,7 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
} }
if (rtnl_open(&rth, 0) < 0) { if (rtnl_open(&rth, 0) < 0) {
exit(1); return 1;
} }
ll_init_map(&rth); ll_init_map(&rth);
@ -589,15 +591,16 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
int idx; int idx;
if (id) { if (id) {
if ((idx = ll_name_to_index(id)) == 0) { idx = ll_name_to_index(id);
bb_error_msg("cannot find device \"%s\"", id); if (idx == 0) {
return -1; bb_error_msg_and_die("cannot find device \"%s\"", id);
} }
filter.iif = idx; filter.iif = idx;
filter.iifmask = -1; filter.iifmask = -1;
} }
if (od) { if (od) {
if ((idx = ll_name_to_index(od)) == 0) { idx = ll_name_to_index(od);
if (idx == 0) {
bb_error_msg("cannot find device \"%s\"", od); bb_error_msg("cannot find device \"%s\"", od);
} }
filter.oif = idx; filter.oif = idx;
@ -622,20 +625,17 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
for (;;) { for (;;) {
if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
perror("Cannot send dump request"); bb_perror_msg_and_die("cannot send dump request");
return -1;
} }
filter.flushed = 0; filter.flushed = 0;
if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
bb_error_msg("flush terminated"); bb_error_msg_and_die("flush terminated");
return -1;
} }
if (filter.flushed == 0) { if (filter.flushed == 0) {
fflush(stdout);
return 0; return 0;
} }
if (flush_update() < 0) if (flush_update())
exit(1); return 1;
} }
} }
@ -653,10 +653,11 @@ static int iproute_list_or_flush(int argc, char **argv, int flush)
bb_error_msg_and_die("dump terminated"); bb_error_msg_and_die("dump terminated");
} }
exit(0); return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int iproute_get(int argc, char **argv) static int iproute_get(int argc, char **argv)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -734,7 +735,8 @@ static int iproute_get(int argc, char **argv)
} }
req.r.rtm_dst_len = addr.bitlen; req.r.rtm_dst_len = addr.bitlen;
} }
argc--; argv++; argc--;
argv++;
} }
} }
@ -743,7 +745,7 @@ static int iproute_get(int argc, char **argv)
} }
if (rtnl_open(&rth, 0) < 0) if (rtnl_open(&rth, 0) < 0)
exit(1); return 1;
ll_init_map(&rth); ll_init_map(&rth);
@ -751,16 +753,16 @@ static int iproute_get(int argc, char **argv)
int idx; int idx;
if (idev) { if (idev) {
if ((idx = ll_name_to_index(idev)) == 0) { idx = ll_name_to_index(idev);
bb_error_msg("cannot find device \"%s\"", idev); if (idx == 0) {
return -1; bb_error_msg_and_die("cannot find device \"%s\"", idev);
} }
addattr32(&req.n, sizeof(req), RTA_IIF, idx); addattr32(&req.n, sizeof(req), RTA_IIF, idx);
} }
if (odev) { if (odev) {
if ((idx = ll_name_to_index(odev)) == 0) { idx = ll_name_to_index(odev);
bb_error_msg("cannot find device \"%s\"", odev); if (idx == 0) {
return -1; bb_error_msg_and_die("cannot find device \"%s\"", odev);
} }
addattr32(&req.n, sizeof(req), RTA_OIF, idx); addattr32(&req.n, sizeof(req), RTA_OIF, idx);
} }
@ -771,7 +773,7 @@ static int iproute_get(int argc, char **argv)
} }
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
exit(2); return 2;
} }
if (connected && !from_ok) { if (connected && !from_ok) {
@ -784,13 +786,11 @@ static int iproute_get(int argc, char **argv)
} }
if (req.n.nlmsg_type != RTM_NEWROUTE) { if (req.n.nlmsg_type != RTM_NEWROUTE) {
bb_error_msg("not a route?"); bb_error_msg_and_die("not a route?");
return -1;
} }
len -= NLMSG_LENGTH(sizeof(*r)); len -= NLMSG_LENGTH(sizeof(*r));
if (len < 0) { if (len < 0) {
bb_error_msg("wrong len %d", len); bb_error_msg_and_die("wrong len %d", len);
return -1;
} }
memset(tb, 0, sizeof(tb)); memset(tb, 0, sizeof(tb));
@ -800,8 +800,7 @@ static int iproute_get(int argc, char **argv)
tb[RTA_PREFSRC]->rta_type = RTA_SRC; tb[RTA_PREFSRC]->rta_type = RTA_SRC;
r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
} else if (!tb[RTA_SRC]) { } else if (!tb[RTA_SRC]) {
bb_error_msg("failed to connect the route"); bb_error_msg_and_die("failed to connect the route");
return -1;
} }
if (!odev && tb[RTA_OIF]) { if (!odev && tb[RTA_OIF]) {
tb[RTA_OIF]->rta_type = 0; tb[RTA_OIF]->rta_type = 0;
@ -816,17 +815,19 @@ static int iproute_get(int argc, char **argv)
req.n.nlmsg_type = RTM_GETROUTE; req.n.nlmsg_type = RTM_GETROUTE;
if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) { if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
exit(2); return 2;
} }
} }
if (print_route(NULL, &req.n, (void*)stdout) < 0) { if (print_route(NULL, &req.n, (void*)stdout) < 0) {
// how is this useful?
bb_error_msg_and_die("an error :-)"); bb_error_msg_and_die("an error :-)");
} }
exit(0); return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
int do_iproute(int argc, char **argv) int do_iproute(int argc, char **argv)
{ {
static const char * const ip_route_commands[] = { static const char * const ip_route_commands[] = {

View File

@ -155,11 +155,12 @@ static int print_rule(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
} else if (r->rtm_type != RTN_UNICAST) } else if (r->rtm_type != RTN_UNICAST)
fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
fprintf(fp, "\n"); fputc('\n', fp);
fflush(fp); fflush(fp);
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int iprule_list(int argc, char **argv) static int iprule_list(int argc, char **argv)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -178,19 +179,18 @@ static int iprule_list(int argc, char **argv)
return 1; return 1;
if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
bb_perror_msg("Cannot send dump request"); bb_perror_msg_and_die("cannot send dump request");
return 1;
} }
if (rtnl_dump_filter(&rth, print_rule, stdout, NULL, NULL) < 0) { if (rtnl_dump_filter(&rth, print_rule, stdout, NULL, NULL) < 0) {
bb_error_msg("Dump terminated"); bb_error_msg_and_die("dump terminated");
return 1;
} }
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int iprule_modify(int cmd, int argc, char **argv) static int iprule_modify(int cmd, int argc, char **argv)
{ {
int table_ok = 0; int table_ok = 0;
@ -282,7 +282,8 @@ static int iprule_modify(int cmd, int argc, char **argv)
if (matches(*argv, "help") == 0) if (matches(*argv, "help") == 0)
bb_show_usage(); bb_show_usage();
if (rtnl_rtntype_a2n(&type, *argv)) if (rtnl_rtntype_a2n(&type, *argv))
invarg("Failed to parse rule type", *argv); // bogus-looking error message "invalid argument 'cannot parse rule type' to '<*argv>'"
invarg("cannot parse rule type", *argv);
req.r.rtm_type = type; req.r.rtm_type = type;
} }
argc--; argc--;
@ -304,6 +305,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
int do_iprule(int argc, char **argv) int do_iprule(int argc, char **argv)
{ {
static const char * const ip_rule_commands[] = static const char * const ip_rule_commands[] =
@ -331,4 +333,3 @@ int do_iprule(int argc, char **argv)
} }
return iprule_modify(cmd, argc-1, argv+1); return iprule_modify(cmd, argc-1, argv+1);
} }

View File

@ -18,9 +18,6 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <net/if.h> #include <net/if.h>
@ -37,6 +34,7 @@
#include "ip_common.h" #include "ip_common.h"
/* Dies on error */
static int do_ioctl_get_ifindex(char *dev) static int do_ioctl_get_ifindex(char *dev)
{ {
struct ifreq ifr; struct ifreq ifr;
@ -45,8 +43,7 @@ static int do_ioctl_get_ifindex(char *dev)
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
if (ioctl(fd, SIOCGIFINDEX, &ifr)) { if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
bb_perror_msg("ioctl"); bb_perror_msg_and_die("SIOCGIFINDEX");
return 0;
} }
close(fd); close(fd);
return ifr.ifr_ifindex; return ifr.ifr_ifindex;
@ -60,31 +57,28 @@ static int do_ioctl_get_iftype(char *dev)
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
bb_perror_msg("ioctl"); bb_perror_msg("SIOCGIFHWADDR");
return -1; return -1;
} }
close(fd); close(fd);
return ifr.ifr_addr.sa_family; return ifr.ifr_addr.sa_family;
} }
static char *do_ioctl_get_ifname(int idx) static char *do_ioctl_get_ifname(int idx)
{ {
static struct ifreq ifr; struct ifreq ifr;
int fd; int fd;
ifr.ifr_ifindex = idx; ifr.ifr_ifindex = idx;
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
if (ioctl(fd, SIOCGIFNAME, &ifr)) { if (ioctl(fd, SIOCGIFNAME, &ifr)) {
bb_perror_msg("ioctl"); bb_perror_msg("SIOCGIFNAME");
return NULL; return NULL;
} }
close(fd); close(fd);
return ifr.ifr_name; return xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
} }
static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p) static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
{ {
struct ifreq ifr; struct ifreq ifr;
@ -96,17 +90,17 @@ static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCGETTUNNEL, &ifr); err = ioctl(fd, SIOCGETTUNNEL, &ifr);
if (err) { if (err) {
bb_perror_msg("ioctl"); bb_perror_msg("SIOCGETTUNNEL");
} }
close(fd); close(fd);
return err; return err;
} }
/* Dies on error, otherwise returns 0 */
static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p) static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd; int fd;
int err;
if (cmd == SIOCCHGTUNNEL && p->name[0]) { if (cmd == SIOCCHGTUNNEL && p->name[0]) {
strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
@ -115,19 +109,18 @@ static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
} }
ifr.ifr_ifru.ifru_data = (void*)p; ifr.ifr_ifru.ifru_data = (void*)p;
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, cmd, &ifr); if (ioctl(fd, cmd, &ifr)) {
if (err) { bb_perror_msg_and_die("ioctl");
bb_perror_msg("ioctl");
} }
close(fd); close(fd);
return err; return 0;
} }
/* Dies on error, otherwise returns 0 */
static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p) static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd; int fd;
int err;
if (p->name[0]) { if (p->name[0]) {
strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
@ -136,15 +129,15 @@ static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
} }
ifr.ifr_ifru.ifru_data = (void*)p; ifr.ifr_ifru.ifru_data = (void*)p;
fd = xsocket(AF_INET, SOCK_DGRAM, 0); fd = xsocket(AF_INET, SOCK_DGRAM, 0);
err = ioctl(fd, SIOCDELTUNNEL, &ifr); if (ioctl(fd, SIOCDELTUNNEL, &ifr)) {
if (err) { bb_perror_msg_and_die("SIOCDELTUNNEL");
bb_perror_msg("ioctl");
} }
close(fd); close(fd);
return err; return 0;
} }
static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) /* Dies on error */
static void parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
{ {
int count = 0; int count = 0;
char medium[IFNAMSIZ]; char medium[IFNAMSIZ];
@ -164,27 +157,23 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
if (strcmp(*argv, "ipip") == 0 || if (strcmp(*argv, "ipip") == 0 ||
strcmp(*argv, "ip/ip") == 0) { strcmp(*argv, "ip/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
bb_error_msg("you managed to ask for more than one tunnel mode"); bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
exit(-1);
} }
p->iph.protocol = IPPROTO_IPIP; p->iph.protocol = IPPROTO_IPIP;
} else if (strcmp(*argv, "gre") == 0 || } else if (strcmp(*argv, "gre") == 0 ||
strcmp(*argv, "gre/ip") == 0) { strcmp(*argv, "gre/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) { if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
bb_error_msg("you managed to ask for more than one tunnel mode"); bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
exit(-1);
} }
p->iph.protocol = IPPROTO_GRE; p->iph.protocol = IPPROTO_GRE;
} else if (strcmp(*argv, "sit") == 0 || } else if (strcmp(*argv, "sit") == 0 ||
strcmp(*argv, "ipv6/ip") == 0) { strcmp(*argv, "ipv6/ip") == 0) {
if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) { if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
bb_error_msg("you managed to ask for more than one tunnel mode"); bb_error_msg_and_die("you managed to ask for more than one tunnel mode");
exit(-1);
} }
p->iph.protocol = IPPROTO_IPV6; p->iph.protocol = IPPROTO_IPV6;
} else { } else {
bb_error_msg("cannot guess tunnel mode"); bb_error_msg_and_die("cannot guess tunnel mode");
exit(-1);
} }
} else if (strcmp(*argv, "key") == 0) { } else if (strcmp(*argv, "key") == 0) {
unsigned uval; unsigned uval;
@ -195,8 +184,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
p->i_key = p->o_key = get_addr32(*argv); p->i_key = p->o_key = get_addr32(*argv);
else { else {
if (get_unsigned(&uval, *argv, 0)<0) { if (get_unsigned(&uval, *argv, 0)<0) {
bb_error_msg("invalid value of \"key\""); bb_error_msg_and_die("invalid value of \"key\"");
exit(-1);
} }
p->i_key = p->o_key = htonl(uval); p->i_key = p->o_key = htonl(uval);
} }
@ -208,8 +196,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
p->o_key = get_addr32(*argv); p->o_key = get_addr32(*argv);
else { else {
if (get_unsigned(&uval, *argv, 0)<0) { if (get_unsigned(&uval, *argv, 0)<0) {
bb_error_msg("invalid value of \"ikey\""); bb_error_msg_and_die("invalid value of \"ikey\"");
exit(-1);
} }
p->i_key = htonl(uval); p->i_key = htonl(uval);
} }
@ -221,8 +208,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
p->o_key = get_addr32(*argv); p->o_key = get_addr32(*argv);
else { else {
if (get_unsigned(&uval, *argv, 0)<0) { if (get_unsigned(&uval, *argv, 0)<0) {
bb_error_msg("invalid value of \"okey\""); bb_error_msg_and_die("invalid value of \"okey\"");
exit(-1);
} }
p->o_key = htonl(uval); p->o_key = htonl(uval);
} }
@ -286,15 +272,15 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
struct ip_tunnel_parm old_p; struct ip_tunnel_parm old_p;
memset(&old_p, 0, sizeof(old_p)); memset(&old_p, 0, sizeof(old_p));
if (do_get_ioctl(*argv, &old_p)) if (do_get_ioctl(*argv, &old_p))
return -1; exit(1);
*p = old_p; *p = old_p;
} }
} }
count++; count++;
argc--; argv++; argc--;
argv++;
} }
if (p->iph.protocol == 0) { if (p->iph.protocol == 0) {
if (memcmp(p->name, "gre", 3) == 0) if (memcmp(p->name, "gre", 3) == 0)
p->iph.protocol = IPPROTO_GRE; p->iph.protocol = IPPROTO_GRE;
@ -306,15 +292,12 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) { if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) { if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
bb_error_msg("keys are not allowed with ipip and sit"); bb_error_msg_and_die("keys are not allowed with ipip and sit");
return -1;
} }
} }
if (medium[0]) { if (medium[0]) {
p->link = do_ioctl_get_ifindex(medium); p->link = do_ioctl_get_ifindex(medium);
if (p->link == 0)
return -1;
} }
if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) { if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
@ -326,23 +309,20 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
p->o_flags |= GRE_KEY; p->o_flags |= GRE_KEY;
} }
if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) { if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
bb_error_msg("broadcast tunnel requires a source address"); bb_error_msg_and_die("broadcast tunnel requires a source address");
return -1;
} }
return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int do_add(int cmd, int argc, char **argv) static int do_add(int cmd, int argc, char **argv)
{ {
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
if (parse_args(argc, argv, cmd, &p) < 0) parse_args(argc, argv, cmd, &p);
return -1;
if (p.iph.ttl && p.iph.frag_off == 0) { if (p.iph.ttl && p.iph.frag_off == 0) {
bb_error_msg("ttl != 0 and noptmudisc are incompatible"); bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
return -1;
} }
switch (p.iph.protocol) { switch (p.iph.protocol) {
@ -353,18 +333,16 @@ static int do_add(int cmd, int argc, char **argv)
case IPPROTO_IPV6: case IPPROTO_IPV6:
return do_add_ioctl(cmd, "sit0", &p); return do_add_ioctl(cmd, "sit0", &p);
default: default:
bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)"); bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)");
return -1;
} }
return -1;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int do_del(int argc, char **argv) static int do_del(int argc, char **argv)
{ {
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0) parse_args(argc, argv, SIOCDELTUNNEL, &p);
return -1;
switch (p.iph.protocol) { switch (p.iph.protocol) {
case IPPROTO_IPIP: case IPPROTO_IPIP:
@ -376,7 +354,6 @@ static int do_del(int argc, char **argv)
default: default:
return do_del_ioctl(p.name, &p); return do_del_ioctl(p.name, &p);
} }
return -1;
} }
static void print_tunnel(struct ip_tunnel_parm *p) static void print_tunnel(struct ip_tunnel_parm *p)
@ -399,8 +376,10 @@ static void print_tunnel(struct ip_tunnel_parm *p)
p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any"); p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");
if (p->link) { if (p->link) {
char *n = do_ioctl_get_ifname(p->link); char *n = do_ioctl_get_ifname(p->link);
if (n) if (n) {
printf(" dev %s ", n); printf(" dev %s ", n);
free(n);
}
} }
if (p->iph.ttl) if (p->iph.ttl)
printf(" ttl %d ", p->iph.ttl); printf(" ttl %d ", p->iph.ttl);
@ -428,16 +407,16 @@ static void print_tunnel(struct ip_tunnel_parm *p)
} }
if (p->i_flags & GRE_SEQ) if (p->i_flags & GRE_SEQ)
printf("%s Drop packets out of sequence.\n", _SL_); printf("%c Drop packets out of sequence.\n", _SL_);
if (p->i_flags & GRE_CSUM) if (p->i_flags & GRE_CSUM)
printf("%s Checksum in received packet is required.", _SL_); printf("%c Checksum in received packet is required.", _SL_);
if (p->o_flags & GRE_SEQ) if (p->o_flags & GRE_SEQ)
printf("%s Sequence packets on output.", _SL_); printf("%c Sequence packets on output.", _SL_);
if (p->o_flags & GRE_CSUM) if (p->o_flags & GRE_CSUM)
printf("%s Checksum output packets.", _SL_); printf("%c Checksum output packets.", _SL_);
} }
static int do_tunnels_list(struct ip_tunnel_parm *p) static void do_tunnels_list(struct ip_tunnel_parm *p)
{ {
char name[IFNAMSIZ]; char name[IFNAMSIZ];
unsigned long rx_bytes, rx_packets, rx_errs, rx_drops, unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
@ -450,8 +429,8 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
FILE *fp = fopen("/proc/net/dev", "r"); FILE *fp = fopen("/proc/net/dev", "r");
if (fp == NULL) { if (fp == NULL) {
perror("fopen"); bb_perror_msg("fopen");
return -1; return;
} }
fgets(buf, sizeof(buf), fp); fgets(buf, sizeof(buf), fp);
@ -465,7 +444,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
if (ptr == NULL || if (ptr == NULL ||
(*ptr++ = 0, sscanf(buf, "%s", name) != 1)) { (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
bb_error_msg("wrong format of /proc/net/dev. Sorry"); bb_error_msg("wrong format of /proc/net/dev. Sorry");
return -1; return;
} }
if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
&rx_bytes, &rx_packets, &rx_errs, &rx_drops, &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
@ -477,7 +456,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
continue; continue;
type = do_ioctl_get_iftype(name); type = do_ioctl_get_iftype(name);
if (type == -1) { if (type == -1) {
bb_error_msg("failed to get type of [%s]", name); bb_error_msg("cannot get type of [%s]", name);
continue; continue;
} }
if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
@ -494,16 +473,15 @@ static int do_tunnels_list(struct ip_tunnel_parm *p)
print_tunnel(&p1); print_tunnel(&p1);
puts(""); puts("");
} }
return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
static int do_show(int argc, char **argv) static int do_show(int argc, char **argv)
{ {
int err; int err;
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) parse_args(argc, argv, SIOCGETTUNNEL, &p);
return -1;
switch (p.iph.protocol) { switch (p.iph.protocol) {
case IPPROTO_IPIP: case IPPROTO_IPIP:
@ -527,6 +505,7 @@ static int do_show(int argc, char **argv)
return 0; return 0;
} }
/* Return value becomes exitcode. It's okay to not return at all */
int do_iptunnel(int argc, char **argv) int do_iptunnel(int argc, char **argv)
{ {
if (argc > 0) { if (argc > 0) {

View File

@ -54,7 +54,7 @@ int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
h = ifi->ifi_index&0xF; h = ifi->ifi_index&0xF;
for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next) for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
if (im->index == ifi->ifi_index) if (im->index == ifi->ifi_index)
break; break;
@ -87,7 +87,7 @@ const char *ll_idx_n2a(int idx, char *buf)
if (idx == 0) if (idx == 0)
return "*"; return "*";
for (im = idxmap[idx&0xF]; im; im = im->next) for (im = idxmap[idx & 0xF]; im; im = im->next)
if (im->index == idx) if (im->index == idx)
return im->name; return im->name;
snprintf(buf, 16, "if%d", idx); snprintf(buf, 16, "if%d", idx);
@ -108,7 +108,7 @@ int ll_index_to_type(int idx)
if (idx == 0) if (idx == 0)
return -1; return -1;
for (im = idxmap[idx&0xF]; im; im = im->next) for (im = idxmap[idx & 0xF]; im; im = im->next)
if (im->index == idx) if (im->index == idx)
return im->type; return im->type;
return -1; return -1;
@ -121,16 +121,18 @@ unsigned ll_index_to_flags(int idx)
if (idx == 0) if (idx == 0)
return 0; return 0;
for (im = idxmap[idx&0xF]; im; im = im->next) for (im = idxmap[idx & 0xF]; im; im = im->next)
if (im->index == idx) if (im->index == idx)
return im->flags; return im->flags;
return 0; return 0;
} }
// TODO: caching is not warranted - no users which repeatedly call it
int ll_name_to_index(char *name) int ll_name_to_index(char *name)
{ {
static char ncache[16]; static char ncache[16];
static int icache; static int icache;
struct idxmap *im; struct idxmap *im;
int sock_fd; int sock_fd;
int i; int i;
@ -139,7 +141,7 @@ int ll_name_to_index(char *name)
return 0; return 0;
if (icache && strcmp(name, ncache) == 0) if (icache && strcmp(name, ncache) == 0)
return icache; return icache;
for (i=0; i<16; i++) { for (i = 0; i < 16; i++) {
for (im = idxmap[i]; im; im = im->next) { for (im = idxmap[i]; im; im = im->next) {
if (strcmp(im->name, name) == 0) { if (strcmp(im->name, name) == 0) {
icache = im->index; icache = im->index;

View File

@ -13,9 +13,6 @@
#include "libbb.h" #include "libbb.h"
#include <string.h>
#include <unistd.h>
#include "utils.h" #include "utils.h"
#include "inet_common.h" #include "inet_common.h"
@ -197,7 +194,7 @@ int get_prefix_1(inet_prefix * dst, char *arg, int family)
dst->bitlen = plen; dst->bitlen = plen;
} }
} }
done: done:
if (slash) if (slash)
*slash = '/'; *slash = '/';
return err; return err;

View File

@ -9,13 +9,12 @@
#include "rtm_map.h" #include "rtm_map.h"
extern int preferred_family; extern int preferred_family;
extern int show_stats; extern smallint show_stats; /* UNUSED */
extern int show_details; extern smallint show_details; /* UNUSED */
extern int show_raw; extern smallint show_raw; /* UNUSED */
extern int resolve_hosts; extern smallint resolve_hosts; /* UNUSED */
extern int oneline; extern smallint oneline;
//FIXME! Appears in two .h files! extern char _SL_;
extern const char * _SL_;
#ifndef IPPROTO_ESP #ifndef IPPROTO_ESP
#define IPPROTO_ESP 50 #define IPPROTO_ESP 50
@ -80,7 +79,7 @@ void invarg(const char *, const char *) ATTRIBUTE_NORETURN;
void duparg(const char *, const char *) ATTRIBUTE_NORETURN; void duparg(const char *, const char *) ATTRIBUTE_NORETURN;
void duparg2(const char *, const char *) ATTRIBUTE_NORETURN; void duparg2(const char *, const char *) ATTRIBUTE_NORETURN;
int matches(const char *arg, const char *pattern); int matches(const char *arg, const char *pattern);
extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits);
const char *dnet_ntop(int af, const void *addr, char *str, size_t len); const char *dnet_ntop(int af, const void *addr, char *str, size_t len);
int dnet_pton(int af, const char *src, void *addr); int dnet_pton(int af, const char *src, void *addr);