Fix dependency for IFUPDOWN_UDHCPC_CMD_OPTIONS
[oweals/busybox.git] / networking / ifenslave.c
index 1e983f2ba448ec172ac5bb5885b0bf8618498a43..1cb765e230d83756ac85531e864f45b9d0e8a865 100644 (file)
  *       - Code cleanup and style changes
  *         set version to 1.1.0
  */
+//config:config IFENSLAVE
+//config:      bool "ifenslave"
+//config:      default y
+//config:      select PLATFORM_LINUX
+//config:      help
+//config:        Userspace application to bind several interfaces
+//config:        to a logical interface (use with kernel bonding driver).
+
+//applet:IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_IFENSLAVE) += ifenslave.o interface.o
+
+//usage:#define ifenslave_trivial_usage
+//usage:       "[-cdf] MASTER_IFACE SLAVE_IFACE..."
+//usage:#define ifenslave_full_usage "\n\n"
+//usage:       "Configure network interfaces for parallel routing\n"
+//usage:     "\n       -c,--change-active      Change active slave"
+//usage:     "\n       -d,--detach             Remove slave interface from bonding device"
+//usage:     "\n       -f,--force              Force, even if interface is not Ethernet"
+/* //usage:  "\n       -r,--receive-slave      Create a receive-only slave" */
+//usage:
+//usage:#define ifenslave_example_usage
+//usage:       "To create a bond device, simply follow these three steps:\n"
+//usage:       "- ensure that the required drivers are properly loaded:\n"
+//usage:       "  # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n"
+//usage:       "- assign an IP address to the bond device:\n"
+//usage:       "  # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n"
+//usage:       "- attach all the interfaces you need to the bond device:\n"
+//usage:       "  # ifenslave bond0 eth0 eth1 eth2\n"
+//usage:       "  If bond0 didn't have a MAC address, it will take eth0's. Then, all\n"
+//usage:       "  interfaces attached AFTER this assignment will get the same MAC addr.\n\n"
+//usage:       "  To detach a dead interface without setting the bond device down:\n"
+//usage:       "  # ifenslave -d bond0 eth1\n\n"
+//usage:       "  To set the bond device down and automatically release all the slaves:\n"
+//usage:       "  # ifconfig bond0 down\n\n"
+//usage:       "  To change active slave:\n"
+//usage:       "  # ifenslave -c bond0 eth0\n"
 
 #include "libbb.h"
 
-#include <net/if_arp.h>
+/* #include <net/if.h> - no. linux/if_bonding.h pulls in linux/if.h */
+#include <linux/if.h>
+//#include <net/if_arp.h> - not needed?
 #include <linux/if_bonding.h>
 #include <linux/sockios.h>
-
-typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */
-typedef uint32_t u32;           /* ditto */
-typedef uint16_t u16;           /* ditto */
-typedef uint8_t u8;             /* ditto */
+#include "fix_u32.h" /* hack, so we may include kernel's ethtool.h */
 #include <linux/ethtool.h>
+#ifndef BOND_ABI_VERSION
+# define BOND_ABI_VERSION 2
+#endif
+#ifndef IFNAMSIZ
+# define IFNAMSIZ 16
+#endif
 
 
 struct dev_data {
@@ -135,11 +176,6 @@ struct globals {
 
 /* NOINLINEs are placed where it results in smaller code (gcc 4.3.1) */
 
-static void strncpy_IFNAMSIZ(char *dst, const char *src)
-{
-       strncpy(dst, src, IFNAMSIZ);
-}
-
 static int ioctl_on_skfd(unsigned request, struct ifreq *ifr)
 {
        return ioctl(skfd, request, ifr);
@@ -147,7 +183,7 @@ static int ioctl_on_skfd(unsigned request, struct ifreq *ifr)
 
 static int set_ifrname_and_do_ioctl(unsigned request, struct ifreq *ifr, const char *ifname)
 {
-        strncpy_IFNAMSIZ(ifr->ifr_name, ifname);
+       strncpy_IFNAMSIZ(ifr->ifr_name, ifname);
        return ioctl_on_skfd(request, ifr);
 }
 
@@ -245,7 +281,7 @@ static int set_if_addr(char *master_ifname, char *slave_ifname)
                if (res < 0) {
                        ifr.ifr_addr.sa_family = AF_INET;
                        memset(ifr.ifr_addr.sa_data, 0,
-                              sizeof(ifr.ifr_addr.sa_data));
+                               sizeof(ifr.ifr_addr.sa_data));
                }
 
                res = set_ifrname_and_do_ioctl(ifra[i].s_ioctl, &ifr, slave_ifname);
@@ -261,9 +297,7 @@ static void change_active(char *master_ifname, char *slave_ifname)
        struct ifreq ifr;
 
        if (!(slave.flags.ifr_flags & IFF_SLAVE)) {
-               bb_error_msg_and_die(
-                       "%s is not a slave",
-                       slave_ifname);
+               bb_error_msg_and_die("%s is not a slave", slave_ifname);
        }
 
        strncpy_IFNAMSIZ(ifr.ifr_slave, slave_ifname);
@@ -402,8 +436,7 @@ static int release(char *master_ifname, char *slave_ifname)
        int res = 0;
 
        if (!(slave.flags.ifr_flags & IFF_SLAVE)) {
-               bb_error_msg("%s is not a slave",
-                       slave_ifname);
+               bb_error_msg("%s is not a slave", slave_ifname);
                return 1;
        }
 
@@ -449,7 +482,7 @@ static NOINLINE void get_drv_info(char *master_ifname)
 }
 
 int ifenslave_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv)
+int ifenslave_main(int argc UNUSED_PARAM, char **argv)
 {
        char *master_ifname, *slave_ifname;
        int rv;
@@ -460,20 +493,21 @@ int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv)
                OPT_d = (1 << 1),
                OPT_f = (1 << 2),
        };
-#if ENABLE_GETOPT_LONG
+#if ENABLE_LONG_OPTS
        static const char ifenslave_longopts[] ALIGN1 =
-               "change-active\0" No_argument "c"
-               "detach\0"        No_argument "d"
-               "force\0"         No_argument "f"
+               "change-active\0"  No_argument "c"
+               "detach\0"         No_argument "d"
+               "force\0"          No_argument "f"
+               /* "all-interfaces\0" No_argument "a" */
                ;
 
        applet_long_options = ifenslave_longopts;
 #endif
        INIT_G();
 
-       opt = getopt32(argv, "cdf");
+       opt = getopt32(argv, "cdfa");
        argv += optind;
-       if (opt & (opt-1)) /* options check */
+       if (opt & (opt-1)) /* Only one option can be given */
                bb_show_usage();
 
        master_ifname = *argv++;
@@ -505,25 +539,25 @@ int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv)
                return EXIT_SUCCESS;
        }
 
-       res = get_if_settings(master_ifname, &master);
-       if (res) {
+       if (get_if_settings(master_ifname, &master)) {
                /* Probably a good reason not to go on */
                bb_perror_msg_and_die("%s: can't get settings", master_ifname);
        }
 
-       /* check if master is indeed a master;
+       /* Check if master is indeed a master;
         * if not then fail any operation
         */
        if (!(master.flags.ifr_flags & IFF_MASTER))
                bb_error_msg_and_die("%s is not a master", master_ifname);
 
-       /* check if master is up; if not then fail any operation */
+       /* Check if master is up; if not then fail any operation */
        if (!(master.flags.ifr_flags & IFF_UP))
                bb_error_msg_and_die("%s is not up", master_ifname);
 
-       /* No opts: neither -c[hange] nor -d[etach] -> it's "enslave" then;
-        * and -f[orce] is not there too */
-       if (!opt) {
+#ifdef WHY_BOTHER
+       /* Neither -c[hange] nor -d[etach] -> it's "enslave" then;
+        * and -f[orce] is not there too. Check that it's ethernet. */
+       if (!(opt & (OPT_d|OPT_c|OPT_f))) {
                /* The family '1' is ARPHRD_ETHER for ethernet. */
                if (master.hwaddr.ifr_hwaddr.sa_family != 1) {
                        bb_error_msg_and_die(
@@ -531,10 +565,11 @@ int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv)
                                master_ifname);
                }
        }
+#endif
 
        /* Accepts only one slave */
        if (opt & OPT_c) {
-               /* change active slave */
+               /* Change active slave */
                if (get_slave_flags(slave_ifname)) {
                        bb_perror_msg_and_die(
                                "%s: can't get flags", slave_ifname);
@@ -543,47 +578,43 @@ int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv)
                return EXIT_SUCCESS;
        }
 
-       /* Accept multiple slaves */
+       /* Accepts multiple slaves */
        res = 0;
        do {
                if (opt & OPT_d) {
-                       /* detach a slave interface from the master */
+                       /* Detach a slave interface from the master */
                        rv = get_slave_flags(slave_ifname);
                        if (rv) {
                                /* Can't work with this slave, */
                                /* remember the error and skip it */
                                bb_perror_msg(
-                                       "skipping %s: can't get flags",
-                                       slave_ifname);
+                                       "skipping %s: can't get %s",
+                                       slave_ifname, "flags");
                                res = rv;
                                continue;
                        }
                        rv = release(master_ifname, slave_ifname);
                        if (rv) {
-                               bb_perror_msg(
-                                       "master %s, slave %s: "
-                                       "can't release",
-                                       master_ifname, slave_ifname);
+                               bb_perror_msg("can't release %s from %s",
+                                       slave_ifname, master_ifname);
                                res = rv;
                        }
                } else {
-                       /* attach a slave interface to the master */
+                       /* Attach a slave interface to the master */
                        rv = get_if_settings(slave_ifname, &slave);
                        if (rv) {
                                /* Can't work with this slave, */
                                /* remember the error and skip it */
                                bb_perror_msg(
-                                       "skipping %s: can't get settings",
-                                       slave_ifname);
+                                       "skipping %s: can't get %s",
+                                       slave_ifname, "settings");
                                res = rv;
                                continue;
                        }
                        rv = enslave(master_ifname, slave_ifname);
                        if (rv) {
-                               bb_perror_msg(
-                                       "master %s, slave %s: "
-                                       "can't enslave",
-                                       master_ifname, slave_ifname);
+                               bb_perror_msg("can't enslave %s to %s",
+                                       slave_ifname, master_ifname);
                                res = rv;
                        }
                }