#include #include #include #include #include #include #include #include "netconf.h" #include "../paths.h" #include "netconf.m" #include #include "internal.h" static NETCONF_HELP_FILE help_dev ("devlist"); static CONFIG_FILE f_dev (PROC_NET_DEV ,help_dev ,CONFIGF_PROBED); static int devlist_read2_2( SSTRINGS &list, bool include_normal, // Include normal device bool include_aliases) // Include aliases { int ret = -1; int skfd = socket (AF_INET,SOCK_DGRAM,0); if (skfd < 0) { perror ("socket"); }else{ struct ifconf ifc; int numreqs = 30; ifc.ifc_buf = NULL; ret = 0; while (1) { ifc.ifc_len = sizeof(struct ifreq) * numreqs; ifc.ifc_buf = (char*)realloc(ifc.ifc_buf, ifc.ifc_len); if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { perror("SIOCGIFCONF"); ret = -1; break; } if (ifc.ifc_len == (int)sizeof(struct ifreq) * numreqs) { /* assume it overflowed and try again */ numreqs += 10; continue; } break; } if (ret == 0){ struct ifreq *ifr = ifc.ifc_req; for (int n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { const char *name = ifr->ifr_name; bool is_alias = strchr(name,':')!=NULL; if (is_alias){ if (include_aliases) list.add (new SSTRING(name)); }else if (include_normal){ list.add (new SSTRING(name)); } ifr++; } ret = list.getnb(); } free(ifc.ifc_buf); } return ret; } static int devlist_read2_0( SSTRINGS &list, bool include_normal, // Include normal device bool include_aliases) // Include aliases { int ret = -1; FILE_CFG *fin = f_dev.fopen ("r"); if (fin != NULL){ char buf[600]; if (fgets(buf,sizeof(buf)-1,fin)!=NULL && fgets(buf,sizeof(buf)-1,fin)!=NULL){ while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char word[600]; str_copyword (word,buf,sizeof(word)); char *pt = strchr(word,':'); if (pt != NULL){ /* #Specification: netconf / proc/net/dev netconf assume that /proc/net/dev has the following format. 2 lines of heading followed by device info. Each line begin by the device name. A device name is ended by :, while an alias has a : in the middle and at the end. */ char *nextpt = strchr(pt+1,':'); if (nextpt != NULL){ if (include_aliases){ *nextpt = '\0'; list.add (new SSTRING(word)); } }else if (include_normal){ *pt = '\0'; list.add (new SSTRING(word)); } } } ret = list.getnb(); } fclose (fin); } return ret; } /* Get the list of all network device including aliases. Return -1 if any errors. Return the number of entry in list. */ static int devlist_read ( bool force_2_0, // Read the devlist using the kernel 2.0 // strategy ? SSTRINGS &list, bool include_normal, // Include normal device bool include_aliases) // Include aliases { /* #Specification: network device / getting the list On kernel 2.0 and later, /proc/net/dev is used to retrieve the list of network interface, including aliases. Additionally, on kernel 2.2 and above, the output of ioctl SIOCGIFCONF on an AF_INET socket is merged in. This way devices with IP 0.0.0.0, and alias devices, are found. On SuSE 6.x, for unknown reason, normal device are not visible using SIOGIFCONF until they are initialised. For normal device (not aliases), /proc/net/dev is reliable anyway. */ int ret = devlist_read2_0(list,include_normal,include_aliases); if (ret == -1) { return -1; } if (kernel_newer(2,2,0) && !force_2_0) { ret = devlist_read2_2(list,include_normal,include_aliases); } if (ret == -1) { return -1; } list.sort(); list.remove_dups(); return list.getnb(); } /* Get the list of all network device including aliases. Return -1 if any errors. Return the number of entry in list. */ int devlist_read ( SSTRINGS &list, bool include_normal, // Include normal device bool include_aliases) // Include aliases { return devlist_read (false,list,include_normal,include_aliases); } /* Get the list of all network device (except aliases). Return -1 if any errors. Return the number of entry in list. */ int devlist_read (SSTRINGS &list) { return devlist_read (list,true,false); } /* Return true if a network device is available in the kernel This function is implemented by reading /proc/net/dev instead of asking the kernel directly. Asking the kernel directly has the side effect of triggering kerneld if the device is not loaded. This is not always what we want. */ bool devlist_devexist (const char *devname) { bool ret = false; SSTRINGS list; bool force_2_0 = strchr(devname,':') == NULL; if (devlist_read(force_2_0,list,true,true)!=-1){ int n = list.getnb(); for (int i=0; icmp(devname)==0){ ret = true; break; } } } return ret; } /* Setup a list of devices in a Combo field */ void devlist_setcombo (FIELD_COMBO *comb) { static const char *tbinter[][2]={ {"eth0", MSG_U(F_FIRSTETH,"First ethernet adaptor")}, {"eth1", MSG_U(F_SECOND,"Second")}, {"eth2", MSG_U(F_THIRD,"Third")}, {"eth3", MSG_U(F_FOURTH,"Fourth")}, {"arc0", MSG_U(F_ARCNET,"Arcnet adaptor")}, {"atp0", MSG_U(F_ATPNET,"Pocket adaptor")}, {"dummy0", MSG_U(F_FIRSTDUM,"First dummy device")}, {"dummy1", MSG_R(F_SECOND)}, {"ppp0", MSG_U(F_FIRSTPPP,"First PPP channel")}, {"ppp1", MSG_R(F_SECOND)}, {"sl0", MSG_U(F_FIRSTSLIP,"First SLIP/CSLIP channel")}, {"sl1", MSG_R(F_SECOND)}, {"tr0", MSG_U(F_FIRSTTKR,"First Token ring adaptor")}, {"tr1", MSG_R(F_SECOND)}, }; for (unsigned int i=0; iaddopt (tbinter[i][0],tbinter[i][1]); } }