source: MondoRescue/branches/stable/mindi-busybox/networking/interface.c @ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 12 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 27.7 KB
RevLine 
[1770]1/* vi: set sw=4 ts=4: */
[821]2/*
3 * stolen from net-tools-1.59 and stripped down for busybox by
4 *          Erik Andersen <andersen@codepoet.org>
5 *
6 * Heavily modified by Manuel Novoa III       Mar 12, 2001
7 *
8 * Added print_bytes_scaled function to reduce code size.
9 * Added some (potentially) missing defines.
10 * Improved display support for -a and for a named interface.
11 *
12 * -----------------------------------------------------------
13 *
14 * ifconfig   This file contains an implementation of the command
15 *              that either displays or sets the characteristics of
16 *              one or more of the system's networking interfaces.
17 *
18 *
19 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
20 *              and others.  Copyright 1993 MicroWalt Corporation
21 *
22 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
23 *
24 * Patched to support 'add' and 'del' keywords for INET(4) addresses
25 * by Mrs. Brisby <mrs.brisby@nimh.org>
26 *
27 * {1.34} - 19980630 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
28 *                     - gettext instead of catgets for i18n
29 *          10/1998  - Andi Kleen. Use interface list primitives.
30 *      20001008 - Bernd Eckenfels, Patch from RH for setting mtu
31 *          (default AF was wrong)
32 */
33
34#include <net/if.h>
35#include <net/if_arp.h>
[1770]36#include "inet_common.h"
37#include "libbb.h"
[821]38
[1770]39#if ENABLE_FEATURE_IPV6
[821]40# define HAVE_AFINET6 1
41#else
42# undef HAVE_AFINET6
43#endif
44
45#define _PATH_PROCNET_DEV               "/proc/net/dev"
46#define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
47
[1770]48#ifdef HAVE_AFINET6
[821]49
50#ifndef _LINUX_IN6_H
51/*
52 *    This is in linux/include/net/ipv6.h.
53 */
54
55struct in6_ifreq {
56    struct in6_addr ifr6_addr;
57    uint32_t ifr6_prefixlen;
58    unsigned int ifr6_ifindex;
59};
60
61#endif
62
[1770]63#endif /* HAVE_AFINET6 */
[821]64
65/* Defines for glibc2.0 users. */
66#ifndef SIOCSIFTXQLEN
67#define SIOCSIFTXQLEN      0x8943
68#define SIOCGIFTXQLEN      0x8942
69#endif
70
71/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
72#ifndef ifr_qlen
73#define ifr_qlen        ifr_ifru.ifru_mtu
74#endif
75
76#ifndef HAVE_TXQUEUELEN
77#define HAVE_TXQUEUELEN 1
78#endif
79
80#ifndef IFF_DYNAMIC
81#define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */
82#endif
83
84/* Display an Internet socket address. */
[1770]85static const char *INET_sprint(struct sockaddr *sap, int numeric)
[821]86{
[1770]87    static char *buff;
[821]88
[1770]89    free(buff);
[821]90    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
[1770]91        return "[NONE SET]";
92    buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00);
93    return buff;
94}
[821]95
[1770]96#ifdef UNUSED_AND_BUGGY
97static int INET_getsock(char *bufp, struct sockaddr *sap)
98{
99    char *sp = bufp, *bp;
100    unsigned int i;
101    unsigned val;
102    struct sockaddr_in *sock_in;
[821]103
[1770]104    sock_in = (struct sockaddr_in *) sap;
105    sock_in->sin_family = AF_INET;
106    sock_in->sin_port = 0;
107
108    val = 0;
109    bp = (char *) &val;
110    for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
111        *sp = toupper(*sp);
112
113        if ((unsigned)(*sp - 'A') <= 5)
114            bp[i] |= (int) (*sp - ('A' - 10));
115        else if (isdigit(*sp))
116            bp[i] |= (int) (*sp - '0');
117        else
118            return -1;
119
120        bp[i] <<= 4;
121        sp++;
122        *sp = toupper(*sp);
123
124        if ((unsigned)(*sp - 'A') <= 5)
125            bp[i] |= (int) (*sp - ('A' - 10));
126        else if (isdigit(*sp))
127            bp[i] |= (int) (*sp - '0');
128        else
129            return -1;
130
131        sp++;
132    }
133    sock_in->sin_addr.s_addr = htonl(val);
134
135    return (sp - bufp);
[821]136}
[1770]137#endif
[821]138
[1770]139static int INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
140{
141    return INET_resolve(bufp, (struct sockaddr_in *) sap, 0);
142/*
143    switch (type) {
144    case 1:
145        return (INET_getsock(bufp, sap));
146    case 256:
147        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1));
148    default:
149        return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0));
150    }
151*/
152}
153
154static const struct aftype inet_aftype = {
[821]155    .name =     "inet",
156    .title =    "DARPA Internet",
157    .af =       AF_INET,
158    .alen =     4,
159    .sprint =   INET_sprint,
[1770]160    .input =    INET_input,
[821]161};
162
[1770]163#ifdef HAVE_AFINET6
[821]164
165/* Display an Internet socket address. */
166/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
[1770]167static const char *INET6_sprint(struct sockaddr *sap, int numeric)
[821]168{
[1770]169    static char *buff;
[821]170
[1770]171    free(buff);
[821]172    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
[1770]173        return "[NONE SET]";
174    buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric);
175    return buff;
[821]176}
177
[1770]178#ifdef UNUSED
179static int INET6_getsock(char *bufp, struct sockaddr *sap)
180{
181    struct sockaddr_in6 *sin6;
182
183    sin6 = (struct sockaddr_in6 *) sap;
184    sin6->sin6_family = AF_INET6;
185    sin6->sin6_port = 0;
186
187    if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
188        return -1;
189
190    return 16;          /* ?;) */
191}
192#endif
193
194static int INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap)
195{
196    return INET6_resolve(bufp, (struct sockaddr_in6 *) sap);
197/*
198    switch (type) {
199    case 1:
200        return (INET6_getsock(bufp, sap));
201    default:
202        return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
203    }
204*/
205}
206
207static const struct aftype inet6_aftype = {
[821]208    .name =     "inet6",
209    .title =    "IPv6",
210    .af =       AF_INET6,
211    .alen =     sizeof(struct in6_addr),
212    .sprint =   INET6_sprint,
[1770]213    .input =    INET6_input,
[821]214};
215
[1770]216#endif /* HAVE_AFINET6 */
[821]217
218/* Display an UNSPEC address. */
219static char *UNSPEC_print(unsigned char *ptr)
220{
[1770]221    static char *buff;
222
[821]223    char *pos;
224    unsigned int i;
225
[1770]226    if (!buff);
227        buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
[821]228    pos = buff;
229    for (i = 0; i < sizeof(struct sockaddr); i++) {
230        /* careful -- not every libc's sprintf returns # bytes written */
231        sprintf(pos, "%02X-", (*ptr++ & 0377));
232        pos += 3;
233    }
234    /* Erase trailing "-".  Works as long as sizeof(struct sockaddr) != 0 */
235    *--pos = '\0';
[1770]236    return buff;
[821]237}
238
239/* Display an UNSPEC socket address. */
[1770]240static const char *UNSPEC_sprint(struct sockaddr *sap, int numeric)
[821]241{
242    if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
[1770]243        return "[NONE SET]";
244    return UNSPEC_print((unsigned char *)sap->sa_data);
[821]245}
246
[1770]247static const struct aftype unspec_aftype = {
248    .name   = "unspec",
249    .title  = "UNSPEC",
250    .af     = AF_UNSPEC,
251    .alen    = 0,
252    .print  = UNSPEC_print,
253    .sprint = UNSPEC_sprint,
[821]254};
255
[1770]256static const struct aftype *const aftypes[] = {
[821]257    &inet_aftype,
[1770]258#ifdef HAVE_AFINET6
[821]259    &inet6_aftype,
260#endif
261    &unspec_aftype,
262    NULL
263};
264
265/* Check our protocol family table for this family. */
[1770]266const struct aftype *get_aftype(const char *name)
[821]267{
[1770]268    const struct aftype *const *afp;
[821]269
270    afp = aftypes;
271    while (*afp != NULL) {
[1770]272        if (!strcmp((*afp)->name, name))
[821]273            return (*afp);
274        afp++;
275    }
[1770]276    return NULL;
[821]277}
278
[1770]279/* Check our protocol family table for this family. */
280static const struct aftype *get_afntype(int af)
[821]281{
[1770]282    const struct aftype *const *afp;
[821]283
284    afp = aftypes;
285    while (*afp != NULL) {
286        if ((*afp)->af == af)
[1770]287            return *afp;
[821]288        afp++;
289    }
[1770]290    return NULL;
[821]291}
292
293struct user_net_device_stats {
294    unsigned long long rx_packets;  /* total packets received       */
295    unsigned long long tx_packets;  /* total packets transmitted    */
296    unsigned long long rx_bytes;    /* total bytes received         */
297    unsigned long long tx_bytes;    /* total bytes transmitted      */
298    unsigned long rx_errors;    /* bad packets received         */
299    unsigned long tx_errors;    /* packet transmit problems     */
300    unsigned long rx_dropped;   /* no space in linux buffers    */
301    unsigned long tx_dropped;   /* no space available in linux  */
302    unsigned long rx_multicast; /* multicast packets received   */
303    unsigned long rx_compressed;
304    unsigned long tx_compressed;
305    unsigned long collisions;
306
307    /* detailed rx_errors: */
308    unsigned long rx_length_errors;
309    unsigned long rx_over_errors;   /* receiver ring buff overflow  */
310    unsigned long rx_crc_errors;    /* recved pkt with crc error    */
311    unsigned long rx_frame_errors;  /* recv'd frame alignment error */
312    unsigned long rx_fifo_errors;   /* recv'r fifo overrun          */
313    unsigned long rx_missed_errors; /* receiver missed packet     */
314    /* detailed tx_errors */
315    unsigned long tx_aborted_errors;
316    unsigned long tx_carrier_errors;
317    unsigned long tx_fifo_errors;
318    unsigned long tx_heartbeat_errors;
319    unsigned long tx_window_errors;
320};
321
322struct interface {
323    struct interface *next, *prev;
324    char name[IFNAMSIZ];    /* interface name        */
325    short type;         /* if type               */
326    short flags;        /* various flags         */
327    int metric;         /* routing metric        */
328    int mtu;            /* MTU value             */
329    int tx_queue_len;   /* transmit queue length */
330    struct ifmap map;   /* hardware setup        */
331    struct sockaddr addr;   /* IP address            */
332    struct sockaddr dstaddr;    /* P-P IP address        */
333    struct sockaddr broadaddr;  /* IP broadcast address  */
334    struct sockaddr netmask;    /* IP network mask       */
335    int has_ip;
336    char hwaddr[32];    /* HW address            */
337    int statistics_valid;
338    struct user_net_device_stats stats; /* statistics            */
339    int keepalive;      /* keepalive value for SLIP */
340    int outfill;        /* outfill value for SLIP */
341};
342
343
[1770]344smallint interface_opt_a;   /* show all interfaces */
[821]345
346static struct interface *int_list, *int_last;
347
348
[1770]349#if 0
[821]350/* like strcmp(), but knows about numbers */
[1770]351except that the freshly added calls to xatoul() brf on ethernet aliases with
352uClibc with e.g.: ife->name='lo'  name='eth0:1'
[821]353static int nstrcmp(const char *a, const char *b)
354{
355    const char *a_ptr = a;
356    const char *b_ptr = b;
357
358    while (*a == *b) {
359        if (*a == '\0') {
360            return 0;
361        }
362        if (!isdigit(*a) && isdigit(*(a+1))) {
363            a_ptr = a+1;
364            b_ptr = b+1;
365        }
366        a++;
367        b++;
368    }
369
370    if (isdigit(*a) && isdigit(*b)) {
[1770]371        return xatoul(a_ptr) > xatoul(b_ptr) ? 1 : -1;
[821]372    }
373    return *a - *b;
374}
[1770]375#endif
[821]376
377static struct interface *add_interface(char *name)
378{
379    struct interface *ife, **nextp, *new;
380
381    for (ife = int_last; ife; ife = ife->prev) {
[1770]382        int n = /*n*/strcmp(ife->name, name);
[821]383
384        if (n == 0)
385            return ife;
386        if (n < 0)
387            break;
388    }
389
390    new = xzalloc(sizeof(*new));
391    safe_strncpy(new->name, name, IFNAMSIZ);
392    nextp = ife ? &ife->next : &int_list;
393    new->prev = ife;
394    new->next = *nextp;
395    if (new->next)
396        new->next->prev = new;
397    else
398        int_last = new;
399    *nextp = new;
400    return new;
401}
402
403static char *get_name(char *name, char *p)
404{
405    /* Extract <name> from nul-terminated p where p matches
406       <name>: after leading whitespace.
407       If match is not made, set name empty and return unchanged p */
408    int namestart=0, nameend=0;
409    while (isspace(p[namestart]))
410        namestart++;
411    nameend=namestart;
412    while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend]))
413        nameend++;
414    if (p[nameend]==':') {
415        if ((nameend-namestart)<IFNAMSIZ) {
416            memcpy(name,&p[namestart],nameend-namestart);
417            name[nameend-namestart]='\0';
418            p=&p[nameend];
419        } else {
420            /* Interface name too large */
421            name[0]='\0';
422        }
423    } else {
424        /* trailing ':' not found - return empty */
425        name[0]='\0';
426    }
427    return p + 1;
428}
429
430/* If scanf supports size qualifiers for %n conversions, then we can
431 * use a modified fmt that simply stores the position in the fields
432 * having no associated fields in the proc string.  Of course, we need
433 * to zero them again when we're done.  But that is smaller than the
434 * old approach of multiple scanf occurrences with large numbers of
435 * args. */
436
[1770]437/* static const char *const ss_fmt[] = { */
[821]438/*  "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */
439/*  "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */
440/*  "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */
441/* }; */
442
443    /* Lie about the size of the int pointed to for %n. */
444#if INT_MAX == LONG_MAX
[1770]445static const char *const ss_fmt[] = {
[821]446    "%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u",
447    "%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u",
448    "%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u"
449};
450#else
[1770]451static const char *const ss_fmt[] = {
[821]452    "%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu",
453    "%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu",
454    "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu"
455};
456
457#endif
458
459static void get_dev_fields(char *bp, struct interface *ife, int procnetdev_vsn)
460{
461    memset(&ife->stats, 0, sizeof(struct user_net_device_stats));
462
463    sscanf(bp, ss_fmt[procnetdev_vsn],
464           &ife->stats.rx_bytes, /* missing for 0 */
465           &ife->stats.rx_packets,
466           &ife->stats.rx_errors,
467           &ife->stats.rx_dropped,
468           &ife->stats.rx_fifo_errors,
469           &ife->stats.rx_frame_errors,
470           &ife->stats.rx_compressed, /* missing for <= 1 */
471           &ife->stats.rx_multicast, /* missing for <= 1 */
472           &ife->stats.tx_bytes, /* missing for 0 */
473           &ife->stats.tx_packets,
474           &ife->stats.tx_errors,
475           &ife->stats.tx_dropped,
476           &ife->stats.tx_fifo_errors,
477           &ife->stats.collisions,
478           &ife->stats.tx_carrier_errors,
479           &ife->stats.tx_compressed /* missing for <= 1 */
480           );
481
482    if (procnetdev_vsn <= 1) {
483        if (procnetdev_vsn == 0) {
484            ife->stats.rx_bytes = 0;
485            ife->stats.tx_bytes = 0;
486        }
487        ife->stats.rx_multicast = 0;
488        ife->stats.rx_compressed = 0;
489        ife->stats.tx_compressed = 0;
490    }
491}
492
493static inline int procnetdev_version(char *buf)
494{
495    if (strstr(buf, "compressed"))
496        return 2;
497    if (strstr(buf, "bytes"))
498        return 1;
499    return 0;
500}
501
[1770]502static int if_readconf(void)
503{
504    int numreqs = 30;
505    struct ifconf ifc;
506    struct ifreq *ifr;
507    int n, err = -1;
508    int skfd;
509
510    ifc.ifc_buf = NULL;
511
512    /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets
513       (as of 2.1.128) */
514    skfd = socket(AF_INET, SOCK_DGRAM, 0);
515    if (skfd < 0) {
516        bb_perror_msg("error: no inet socket available");
517        return -1;
518    }
519
520    for (;;) {
521        ifc.ifc_len = sizeof(struct ifreq) * numreqs;
522        ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len);
523
524        if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) {
525            goto out;
526        }
527        if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) {
528            /* assume it overflowed and try again */
529            numreqs += 10;
530            continue;
531        }
532        break;
533    }
534
535    ifr = ifc.ifc_req;
536    for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
537        add_interface(ifr->ifr_name);
538        ifr++;
539    }
540    err = 0;
541
542 out:
543    close(skfd);
544    free(ifc.ifc_buf);
545    return err;
546}
547
[821]548static int if_readlist_proc(char *target)
549{
[1770]550    static smallint proc_read;
551
[821]552    FILE *fh;
553    char buf[512];
554    struct interface *ife;
555    int err, procnetdev_vsn;
556
557    if (proc_read)
558        return 0;
559    if (!target)
560        proc_read = 1;
561
562    fh = fopen(_PATH_PROCNET_DEV, "r");
563    if (!fh) {
[1770]564        bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV);
[821]565        return if_readconf();
566    }
567    fgets(buf, sizeof buf, fh); /* eat line */
568    fgets(buf, sizeof buf, fh);
569
570    procnetdev_vsn = procnetdev_version(buf);
571
572    err = 0;
573    while (fgets(buf, sizeof buf, fh)) {
574        char *s, name[128];
575
576        s = get_name(name, buf);
577        ife = add_interface(name);
578        get_dev_fields(s, ife, procnetdev_vsn);
579        ife->statistics_valid = 1;
580        if (target && !strcmp(target, name))
581            break;
582    }
583    if (ferror(fh)) {
[1770]584        bb_perror_msg(_PATH_PROCNET_DEV);
[821]585        err = -1;
586        proc_read = 0;
587    }
588    fclose(fh);
589    return err;
590}
591
592static int if_readlist(void)
593{
594    int err = if_readlist_proc(NULL);
[1770]595    /* Needed in order to get ethN:M aliases */
[821]596    if (!err)
597        err = if_readconf();
598    return err;
599}
600
601/* Fetch the interface configuration from the kernel. */
602static int if_fetch(struct interface *ife)
603{
604    struct ifreq ifr;
605    char *ifname = ife->name;
[1770]606    int skfd;
[821]607
[1770]608    skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
609
610    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
611    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
612        close(skfd);
613        return -1;
614    }
[821]615    ife->flags = ifr.ifr_flags;
616
[1770]617    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
618    memset(ife->hwaddr, 0, 32);
619    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0)
[821]620        memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);
621
622    ife->type = ifr.ifr_hwaddr.sa_family;
623
[1770]624    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
625    ife->metric = 0;
626    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0)
[821]627        ife->metric = ifr.ifr_metric;
628
[1770]629    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
630    ife->mtu = 0;
631    if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0)
[821]632        ife->mtu = ifr.ifr_mtu;
633
[1770]634    memset(&ife->map, 0, sizeof(struct ifmap));
[821]635#ifdef SIOCGIFMAP
[1770]636    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
[821]637    if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0)
638        ife->map = ifr.ifr_map;
639#endif
640
641#ifdef HAVE_TXQUEUELEN
[1770]642    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
643    ife->tx_queue_len = -1; /* unknown value */
644    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0)
[821]645        ife->tx_queue_len = ifr.ifr_qlen;
646#else
647    ife->tx_queue_len = -1; /* unknown value */
648#endif
649
[1770]650    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
651    ifr.ifr_addr.sa_family = AF_INET;
652    memset(&ife->addr, 0, sizeof(struct sockaddr));
653    if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
654        ife->has_ip = 1;
655        ife->addr = ifr.ifr_addr;
656        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
657        memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
658        if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0)
659            ife->dstaddr = ifr.ifr_dstaddr;
[821]660
[1770]661        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
662        memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
663        if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0)
664            ife->broadaddr = ifr.ifr_broadaddr;
[821]665
[1770]666        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
667        memset(&ife->netmask, 0, sizeof(struct sockaddr));
668        if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0)
669            ife->netmask = ifr.ifr_netmask;
[821]670    }
671
[1770]672    close(skfd);
[821]673    return 0;
674}
675
676
677static int do_if_fetch(struct interface *ife)
678{
679    if (if_fetch(ife) < 0) {
[1770]680        const char *errmsg;
[821]681
682        if (errno == ENODEV) {
683            /* Give better error message for this case. */
684            errmsg = "Device not found";
685        } else {
686            errmsg = strerror(errno);
687        }
688        bb_error_msg("%s: error fetching interface information: %s",
689                ife->name, errmsg);
690        return -1;
691    }
692    return 0;
693}
694
695static const struct hwtype unspec_hwtype = {
696    .name =     "unspec",
697    .title =    "UNSPEC",
698    .type =     -1,
699    .print =    UNSPEC_print
700};
701
702static const struct hwtype loop_hwtype = {
703    .name =     "loop",
704    .title =    "Local Loopback",
705    .type =     ARPHRD_LOOPBACK
706};
707
708#include <net/if_arp.h>
709
[1770]710#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
[821]711#include <net/ethernet.h>
712#else
713#include <linux/if_ether.h>
714#endif
715
716/* Display an Ethernet address in readable format. */
717static char *pr_ether(unsigned char *ptr)
718{
[1770]719    static char *buff;
[821]720
[1770]721    free(buff);
722    buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
[821]723             (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
724             (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
725        );
[1770]726    return buff;
[821]727}
728
[1770]729static int in_ether(const char *bufp, struct sockaddr *sap);
730
[821]731static const struct hwtype ether_hwtype = {
732    .name =     "ether",
733    .title =    "Ethernet",
734    .type =     ARPHRD_ETHER,
735    .alen =     ETH_ALEN,
[1770]736    .print =    pr_ether,
737    .input =    in_ether
[821]738};
739
[1770]740static unsigned hexchar2int(char c)
741{
742    if (isdigit(c))
743        return c - '0';
744    c &= ~0x20; /* a -> A */
745    if ((unsigned)(c - 'A') <= 5)
746        return c - ('A' - 10);
747    return ~0U;
748}
749
750/* Input an Ethernet address and convert to binary. */
751static int in_ether(const char *bufp, struct sockaddr *sap)
752{
753    unsigned char *ptr;
754    char c;
755    int i;
756    unsigned val;
757
758    sap->sa_family = ether_hwtype.type;
759    ptr = (unsigned char*) sap->sa_data;
760
761    i = 0;
762    while ((*bufp != '\0') && (i < ETH_ALEN)) {
763        val = hexchar2int(*bufp++) * 0x10;
764        if (val > 0xff) {
765            errno = EINVAL;
766            return -1;
767        }
768        c = *bufp;
769        if (c == ':' || c == 0)
770            val >>= 4;
771        else {
772            val |= hexchar2int(c);
773            if (val > 0xff) {
774                errno = EINVAL;
775                return -1;
776            }
777        }
778        if (c != 0)
779            bufp++;
780        *ptr++ = (unsigned char) val;
781        i++;
782
783        /* We might get a semicolon here - not required. */
784        if (*bufp == ':') {
785            bufp++;
786        }
787    }
788    return 0;
789}
790
[821]791#include <net/if_arp.h>
792
793static const struct hwtype ppp_hwtype = {
794    .name =     "ppp",
795    .title =    "Point-to-Point Protocol",
796    .type =     ARPHRD_PPP
797};
798
[1770]799#if ENABLE_FEATURE_IPV6
[821]800static const struct hwtype sit_hwtype = {
801    .name =         "sit",
802    .title =        "IPv6-in-IPv4",
803    .type =         ARPHRD_SIT,
804    .print =        UNSPEC_print,
805    .suppress_null_addr =   1
[1770]806};
[821]807#endif
808
[1770]809static const struct hwtype *const hwtypes[] = {
[821]810    &loop_hwtype,
811    &ether_hwtype,
812    &ppp_hwtype,
813    &unspec_hwtype,
[1770]814#if ENABLE_FEATURE_IPV6
[821]815    &sit_hwtype,
816#endif
817    NULL
818};
819
820#ifdef IFF_PORTSEL
[1770]821static const char *const if_port_text[] = {
[821]822    /* Keep in step with <linux/netdevice.h> */
823    "unknown",
824    "10base2",
825    "10baseT",
826    "AUI",
827    "100baseT",
828    "100baseTX",
829    "100baseFX",
830    NULL
831};
832#endif
833
834/* Check our hardware type table for this type. */
[1770]835const struct hwtype *get_hwtype(const char *name)
[821]836{
[1770]837    const struct hwtype *const *hwp;
[821]838
839    hwp = hwtypes;
840    while (*hwp != NULL) {
[1770]841        if (!strcmp((*hwp)->name, name))
[821]842            return (*hwp);
843        hwp++;
844    }
[1770]845    return NULL;
[821]846}
847
[1770]848/* Check our hardware type table for this type. */
849const struct hwtype *get_hwntype(int type)
850{
851    const struct hwtype *const *hwp;
852
853    hwp = hwtypes;
854    while (*hwp != NULL) {
855        if ((*hwp)->type == type)
856            return *hwp;
857        hwp++;
858    }
859    return NULL;
860}
861
[821]862/* return 1 if address is all zeros */
863static int hw_null_address(const struct hwtype *hw, void *ap)
864{
865    unsigned int i;
866    unsigned char *address = (unsigned char *) ap;
867
868    for (i = 0; i < hw->alen; i++)
869        if (address[i])
870            return 0;
871    return 1;
872}
873
[1770]874static const char TRext[] ALIGN1 = "\0\0\0Ki\0Mi\0Gi\0Ti";
[821]875
876static void print_bytes_scaled(unsigned long long ull, const char *end)
877{
878    unsigned long long int_part;
879    const char *ext;
880    unsigned int frac_part;
881    int i;
882
883    frac_part = 0;
884    ext = TRext;
885    int_part = ull;
886    i = 4;
887    do {
888        if (int_part >= 1024) {
889            frac_part = ((((unsigned int) int_part) & (1024-1)) * 10) / 1024;
890            int_part /= 1024;
891            ext += 3;   /* KiB, MiB, GiB, TiB */
892        }
893        --i;
894    } while (i);
895
896    printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end);
897}
898
899static void ife_print(struct interface *ptr)
900{
[1770]901    const struct aftype *ap;
[821]902    const struct hwtype *hw;
903    int hf;
904    int can_compress = 0;
905
[1770]906#ifdef HAVE_AFINET6
[821]907    FILE *f;
908    char addr6[40], devname[20];
909    struct sockaddr_in6 sap;
910    int plen, scope, dad_status, if_idx;
911    char addr6p[8][5];
912#endif
913
914    ap = get_afntype(ptr->addr.sa_family);
915    if (ap == NULL)
916        ap = get_afntype(0);
917
918    hf = ptr->type;
919
920    if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6)
921        can_compress = 1;
922
923    hw = get_hwntype(hf);
924    if (hw == NULL)
925        hw = get_hwntype(-1);
926
927    printf("%-9.9s Link encap:%s  ", ptr->name, hw->title);
928    /* For some hardware types (eg Ash, ATM) we don't print the
929       hardware address if it's null.  */
930    if (hw->print != NULL && (!(hw_null_address(hw, ptr->hwaddr) &&
931                                hw->suppress_null_addr)))
932        printf("HWaddr %s  ", hw->print((unsigned char *)ptr->hwaddr));
933#ifdef IFF_PORTSEL
934    if (ptr->flags & IFF_PORTSEL) {
935        printf("Media:%s", if_port_text[ptr->map.port] /* [0] */);
936        if (ptr->flags & IFF_AUTOMEDIA)
937            printf("(auto)");
938    }
939#endif
[1770]940    puts("");
[821]941
942    if (ptr->has_ip) {
943        printf("          %s addr:%s ", ap->name,
944               ap->sprint(&ptr->addr, 1));
945        if (ptr->flags & IFF_POINTOPOINT) {
946            printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1));
947        }
948        if (ptr->flags & IFF_BROADCAST) {
949            printf(" Bcast:%s ", ap->sprint(&ptr->broadaddr, 1));
950        }
951        printf(" Mask:%s\n", ap->sprint(&ptr->netmask, 1));
952    }
953
[1770]954#ifdef HAVE_AFINET6
[821]955
956#define IPV6_ADDR_ANY           0x0000U
957
958#define IPV6_ADDR_UNICAST       0x0001U
959#define IPV6_ADDR_MULTICAST     0x0002U
960#define IPV6_ADDR_ANYCAST       0x0004U
961
962#define IPV6_ADDR_LOOPBACK      0x0010U
963#define IPV6_ADDR_LINKLOCAL     0x0020U
964#define IPV6_ADDR_SITELOCAL     0x0040U
965
966#define IPV6_ADDR_COMPATv4      0x0080U
967
968#define IPV6_ADDR_SCOPE_MASK    0x00f0U
969
970#define IPV6_ADDR_MAPPED        0x1000U
971#define IPV6_ADDR_RESERVED      0x2000U /* reserved address space */
972
[1770]973    f = fopen(_PATH_PROCNET_IFINET6, "r");
974    if (f != NULL) {
[821]975        while (fscanf
[1770]976               (f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
[821]977                addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4],
978                addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
[1770]979                &dad_status, devname) != EOF
980        ) {
[821]981            if (!strcmp(devname, ptr->name)) {
982                sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
983                        addr6p[0], addr6p[1], addr6p[2], addr6p[3],
984                        addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
985                inet_pton(AF_INET6, addr6,
986                          (struct sockaddr *) &sap.sin6_addr);
987                sap.sin6_family = AF_INET6;
988                printf("          inet6 addr: %s/%d",
[1770]989                       INET6_sprint((struct sockaddr *) &sap, 1),
[821]990                       plen);
991                printf(" Scope:");
992                switch (scope & IPV6_ADDR_SCOPE_MASK) {
993                case 0:
[1770]994                    puts("Global");
[821]995                    break;
996                case IPV6_ADDR_LINKLOCAL:
[1770]997                    puts("Link");
[821]998                    break;
999                case IPV6_ADDR_SITELOCAL:
[1770]1000                    puts("Site");
[821]1001                    break;
1002                case IPV6_ADDR_COMPATv4:
[1770]1003                    puts("Compat");
[821]1004                    break;
1005                case IPV6_ADDR_LOOPBACK:
[1770]1006                    puts("Host");
[821]1007                    break;
1008                default:
[1770]1009                    puts("Unknown");
[821]1010                }
1011            }
1012        }
1013        fclose(f);
1014    }
1015#endif
1016
1017    printf("          ");
1018    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */
1019
1020    if (ptr->flags == 0) {
1021        printf("[NO FLAGS] ");
1022    } else {
[1770]1023        static const char ife_print_flags_strs[] ALIGN1 =
1024            "UP\0"
1025            "BROADCAST\0"
1026            "DEBUG\0"
1027            "LOOPBACK\0"
1028            "POINTOPOINT\0"
1029            "NOTRAILERS\0"
1030            "RUNNING\0"
1031            "NOARP\0"
1032            "PROMISC\0"
1033            "ALLMULTI\0"
1034            "SLAVE\0"
1035            "MASTER\0"
1036            "MULTICAST\0"
1037#ifdef HAVE_DYNAMIC
1038            "DYNAMIC\0"
1039#endif
1040            ;
1041        static const unsigned short ife_print_flags_mask[] ALIGN2 = {
1042            IFF_UP,
1043            IFF_BROADCAST,
1044            IFF_DEBUG,
1045            IFF_LOOPBACK,
1046            IFF_POINTOPOINT,
1047            IFF_NOTRAILERS,
1048            IFF_RUNNING,
1049            IFF_NOARP,
1050            IFF_PROMISC,
1051            IFF_ALLMULTI,
1052            IFF_SLAVE,
1053            IFF_MASTER,
1054            IFF_MULTICAST
1055#ifdef HAVE_DYNAMIC
1056            ,IFF_DYNAMIC
1057#endif
1058        };
1059        const unsigned short *mask = ife_print_flags_mask;
1060        const char *str = ife_print_flags_strs;
[821]1061        do {
[1770]1062            if (ptr->flags & *mask) {
1063                printf("%s ", str);
[821]1064            }
[1770]1065            mask++;
1066            str += strlen(str) + 1;
1067        } while (*str);
[821]1068    }
1069
1070    /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */
1071    printf(" MTU:%d  Metric:%d", ptr->mtu, ptr->metric ? ptr->metric : 1);
1072#ifdef SIOCSKEEPALIVE
1073    if (ptr->outfill || ptr->keepalive)
1074        printf("  Outfill:%d  Keepalive:%d", ptr->outfill, ptr->keepalive);
1075#endif
[1770]1076    puts("");
[821]1077
1078    /* If needed, display the interface statistics. */
1079
1080    if (ptr->statistics_valid) {
1081        /* XXX: statistics are currently only printed for the primary address,
1082         *      not for the aliases, although strictly speaking they're shared
1083         *      by all addresses.
1084         */
1085        printf("          ");
1086
1087        printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n",
1088               ptr->stats.rx_packets, ptr->stats.rx_errors,
1089               ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors,
1090               ptr->stats.rx_frame_errors);
1091        if (can_compress)
1092            printf("             compressed:%lu\n",
1093                   ptr->stats.rx_compressed);
1094        printf("          ");
1095        printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n",
1096               ptr->stats.tx_packets, ptr->stats.tx_errors,
1097               ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors,
1098               ptr->stats.tx_carrier_errors);
1099        printf("          collisions:%lu ", ptr->stats.collisions);
1100        if (can_compress)
1101            printf("compressed:%lu ", ptr->stats.tx_compressed);
1102        if (ptr->tx_queue_len != -1)
1103            printf("txqueuelen:%d ", ptr->tx_queue_len);
1104        printf("\n          R");
1105        print_bytes_scaled(ptr->stats.rx_bytes, "  T");
1106        print_bytes_scaled(ptr->stats.tx_bytes, "\n");
1107
1108    }
1109
1110    if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma ||
1111         ptr->map.base_addr)) {
1112        printf("          ");
1113        if (ptr->map.irq)
1114            printf("Interrupt:%d ", ptr->map.irq);
1115        if (ptr->map.base_addr >= 0x100)    /* Only print devices using it for
1116                                               I/O maps */
1117            printf("Base address:0x%lx ",
1118                   (unsigned long) ptr->map.base_addr);
1119        if (ptr->map.mem_start) {
1120            printf("Memory:%lx-%lx ", ptr->map.mem_start,
1121                   ptr->map.mem_end);
1122        }
1123        if (ptr->map.dma)
1124            printf("DMA chan:%x ", ptr->map.dma);
[1770]1125        puts("");
[821]1126    }
[1770]1127    puts("");
[821]1128}
1129
1130
[1770]1131static int do_if_print(struct interface *ife) /*, int *opt_a)*/
[821]1132{
1133    int res;
1134
1135    res = do_if_fetch(ife);
1136    if (res >= 0) {
[1770]1137        if ((ife->flags & IFF_UP) || interface_opt_a)
[821]1138            ife_print(ife);
1139    }
1140    return res;
1141}
1142
1143static struct interface *lookup_interface(char *name)
1144{
1145    struct interface *ife = NULL;
1146
1147    if (if_readlist_proc(name) < 0)
1148        return NULL;
1149    ife = add_interface(name);
1150    return ife;
1151}
1152
[1770]1153#ifdef UNUSED
1154static int for_all_interfaces(int (*doit) (struct interface *, void *),
1155                              void *cookie)
1156{
1157    struct interface *ife;
1158
1159    if (!int_list && (if_readlist() < 0))
1160        return -1;
1161    for (ife = int_list; ife; ife = ife->next) {
1162        int err = doit(ife, cookie);
1163
1164        if (err)
1165            return err;
1166    }
1167    return 0;
1168}
1169#endif
1170
[821]1171/* for ipv4 add/del modes */
1172static int if_print(char *ifname)
1173{
[1770]1174    struct interface *ife;
[821]1175    int res;
1176
1177    if (!ifname) {
[1770]1178        /*res = for_all_interfaces(do_if_print, &interface_opt_a);*/
1179        if (!int_list && (if_readlist() < 0))
1180            return -1;
1181        for (ife = int_list; ife; ife = ife->next) {
1182            int err = do_if_print(ife); /*, &interface_opt_a);*/
1183            if (err)
1184                return err;
1185        }
1186        return 0;
[821]1187    }
[1770]1188    ife = lookup_interface(ifname);
1189    res = do_if_fetch(ife);
1190    if (res >= 0)
1191        ife_print(ife);
[821]1192    return res;
1193}
1194
1195int display_interfaces(char *ifname)
1196{
1197    int status;
1198
[1770]1199    status = if_print(ifname);
[821]1200
[1770]1201    return (status < 0); /* status < 0 == 1 -- error */
[821]1202}
Note: See TracBrowser for help on using the repository browser.