ifconfig 源码分析

来源:互联网 发布:office 2013 mac 编辑:程序博客网 时间:2024/05/01 00:45

int main(int argc, char **argv)
{  
   ……
    argc--;
    argv++;
   
    while (argc && *argv[0] == '-')

    {
       ……
     }

   打开内核支持的所有协议的套接字,主要是一个循环调用socket的过程
    if ((skfd = sockets_open(0)) < 0)

      {
        perror("socket");
        exit(1);
      }


    if (argc == 0)

      {
        int err = if_print((char *) NULL);
        (void) close(skfd);
        exit(err < 0);
      }
   
    spp = argv;
    safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
    if (*spp == (char *) NULL)

      {
        int err = if_print(ifr.ifr_name);
        (void) close(skfd);
        exit(err < 0);
      }


    if ((ap = get_aftype(*spp)) != NULL)
        spp++;
    else
        ap = get_aftype(DFLT_AF);
       
    if (ap)

     {
        addr_family = ap->af;
        skfd = ap->fd;
     }

  
   while (*spp != (char *) NULL)

        {
   
        }


    switch (ap->af)

    {
    ……
    r = ioctl(fd, SIOCSIFADDR, &ifr);
    ……
     }
在主函数中判断argc,如果仅仅是输入了ifconfig而没有任何参数,则输出全部网卡信息
   
    if (argc == 0)

      {
        int err = if_print((char *) NULL);
        (void) close(skfd);
        exit(err < 0);
     }
   
   
函数if_print 定义在ifconfig.c中,用来输出网卡地址等信息:
static int if_print(char *ifname)
{
    int res;

    if (ife_short)                //如果是以省略模式输出
        printf(_("Iface   MTU Met    RX-OK RX-ERR RX-DRP RX-OVR    TX-OK TX-ERR TX-DRP TX-OVR Flg/n"));

    if (!ifname)

      {                   

         //如果ifname==NULL,则表示输出全部网卡的信息
        res = for_all_interfaces(do_if_print, &opt_a);
      }

   else {  

                      //否则仅仅输出ifname的。
        struct interface *ife;

        ife = lookup_interface(ifname);
        res = do_if_fetch(ife);
        if (res >= 0)
            ife_print(ife);
    }
    return res;
}

这里,又涉及到两个函数的调用:for_all_interfaces和lookup_interface。先来看for_all_interfaces
函数在interface.c中实现:
参数int (*doit) (struct interface *, void *)是一个指向函数的指针,为实际的功能函数,在上层函数中传递过来的是do_if_print
int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)
{
    struct interface *ife;

    if (!int_list && (if_readlist() < 0))
        return -1;
    for (ife = int_list; ife; ife = ife->next) {
        int err = doit(ife, cookie);                //调用函数do_if_print实现
        if (err)
            return err;
    }
    return 0;
}


int do_if_print(struct interface *ife, void *cookie)
{
    int *opt_a = (int *) cookie;
    int res;

    res = do_if_fetch(ife);                         //提取出网卡的信息,置于结构ife中,顺便检查一下设备的合法性,如是否存在等等……
    if (res >= 0) {   
        if ((ife->flags & IFF_UP) || *opt_a)
            ife_print(ife);                        //输出
    }
    return res;
}

int do_if_fetch(struct interface *ife)
{
    if (if_fetch(ife) < 0) {
        char *errmsg;
        if (errno == ENODEV) {
            
            errmsg = _("Device not found");
        } else {
            errmsg = strerror(errno);
        }
          fprintf(stderr, _("%s: error fetching interface information: %s/n"),
                ife->name, errmsg);
        return -1;
    }
    return 0;
}


int if_fetch(struct interface *ife)
{
    struct ifreq ifr;
    int fd;
    char *ifname = ife->name;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)                       
        return (-1);
    ife->flags = ifr.ifr_flags;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
        memset(ife->hwaddr, 0, 32);
    else
        memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8);

    ife->type = ifr.ifr_hwaddr.sa_family;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0)
        ife->metric = 0;
    else
        ife->metric = ifr.ifr_metric;

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
        ife->mtu = 0;
    else
        ife->mtu = ifr.ifr_mtu;

#ifdef HAVE_HWSLIP
    if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP ||
        ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 ||
        ife->type == ARPHRD_ADAPT) {
#ifdef SIOCGOUTFILL
        strcpy(ifr.ifr_name, ifname);
        if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0)
            ife->outfill = 0;
        else
            ife->outfill = (unsigned int) ifr.ifr_data;
#endif
#ifdef SIOCGKEEPALIVE
        strcpy(ifr.ifr_name, ifname);
        if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0)
            ife->keepalive = 0;
        else
            ife->keepalive = (unsigned int) ifr.ifr_data;
#endif
    }
#endif

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
        memset(&ife->map, 0, sizeof(struct ifmap));
    else
        memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap));

    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
        memset(&ife->map, 0, sizeof(struct ifmap));
    else
        ife->map = ifr.ifr_map;

#ifdef HAVE_TXQUEUELEN
    strcpy(ifr.ifr_name, ifname);
    if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0)
        ife->tx_queue_len = -1;       
    else
        ife->tx_queue_len = ifr.ifr_qlen;
#else
    ife->tx_queue_len = -1;       
#endif

#if HAVE_AFINET
   
    fd = get_socket_for_af(AF_INET);
    if (fd >= 0) {
        strcpy(ifr.ifr_name, ifname);
        ifr.ifr_addr.sa_family = AF_INET;
        if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
            ife->has_ip = 1;
            ife->addr = ifr.ifr_addr;
            strcpy(ifr.ifr_name, ifname);
            if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0)
                memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
            else
                ife->dstaddr = ifr.ifr_dstaddr;

            strcpy(ifr.ifr_name, ifname);
            if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0)
                memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
            else
                ife->broadaddr = ifr.ifr_broadaddr;

            strcpy(ifr.ifr_name, ifname);
            if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0)
                memset(&ife->netmask, 0, sizeof(struct sockaddr));
            else
                ife->netmask = ifr.ifr_netmask;
        } else
            memset(&ife->addr, 0, sizeof(struct sockaddr));
    }
#endif

#if HAVE_AFATALK
   
    fd = get_socket_for_af(AF_APPLETALK);
    if (fd >= 0) {
        strcpy(ifr.ifr_name, ifname);
        if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
            ife->ddpaddr = ifr.ifr_addr;
            ife->has_ddp = 1;
        }
    }
#endif

#if HAVE_AFIPX
   
    fd = get_socket_for_af(AF_IPX);
    if (fd >= 0) {
        strcpy(ifr.ifr_name, ifname);
        if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) {
            ife->has_ipx_bb = 1;
            ife->ipxaddr_bb = ifr.ifr_addr;
        }
        strcpy(ifr.ifr_name, ifname);
        if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) {
            ife->has_ipx_sn = 1;
            ife->ipxaddr_sn = ifr.ifr_addr;
        }
        strcpy(ifr.ifr_name, ifname);
        if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) {
            ife->has_ipx_e3 = 1;
            ife->ipxaddr_e3 = ifr.ifr_addr;
        }
        strcpy(ifr.ifr_name, ifname);
        if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) {
            ife->has_ipx_e2 = 1;
            ife->ipxaddr_e2 = ifr.ifr_addr;
        }
    }
#endif

#if HAVE_AFECONET
   
    fd = get_socket_for_af(AF_ECONET);
    if (fd >= 0) {
        strcpy(ifr.ifr_name, ifname);
        if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
            ife->ecaddr = ifr.ifr_addr;
            ife->has_econet = 1;
        }
    }
#endif

    return 0;
}

ife_print 仅仅是根据标志来判断是省略模式输出还是详细模式输出:
void ife_print(struct interface *i)
{
    if (ife_short)
        ife_print_short(i);
    else
        ife_print_long(i);
}

以详细模式为例,其实就是一个printf 的过程,读取后的参数都放在结构struct interface 中……大家可以对照Linux 中输出命令look一下就明白了!

原创粉丝点击