Changeset View
Standalone View
sbin/ifconfig/ifconfig.c
Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
static int ifconfig(int argc, char *const *argv, int iscreate, | static int ifconfig(int argc, char *const *argv, int iscreate, | ||||
const struct afswtch *afp); | const struct afswtch *afp); | ||||
static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, | static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, | ||||
struct ifaddrs *ifa); | struct ifaddrs *ifa); | ||||
static void tunnel_status(int s); | static void tunnel_status(int s); | ||||
static _Noreturn void usage(void); | static _Noreturn void usage(void); | ||||
static int getifflags(const char *ifname, int us); | |||||
static struct afswtch *af_getbyname(const char *name); | static struct afswtch *af_getbyname(const char *name); | ||||
static struct afswtch *af_getbyfamily(int af); | static struct afswtch *af_getbyfamily(int af); | ||||
static void af_other_status(int); | static void af_other_status(int); | ||||
void printifnamemaybe(void); | void printifnamemaybe(void); | ||||
static struct option *opts = NULL; | static struct option *opts = NULL; | ||||
▲ Show 20 Lines • Show All 242 Lines • ▼ Show 20 Lines | main(int argc, char *argv[]) | ||||
struct ifreq paifr; | struct ifreq paifr; | ||||
const struct sockaddr_dl *sdl; | const struct sockaddr_dl *sdl; | ||||
char options[1024], *cp, *envformat, *namecp = NULL; | char options[1024], *cp, *envformat, *namecp = NULL; | ||||
struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); | struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); | ||||
struct ifa_order_elt *cur, *tmp; | struct ifa_order_elt *cur, *tmp; | ||||
const char *ifname; | const char *ifname; | ||||
struct option *p; | struct option *p; | ||||
size_t iflen; | size_t iflen; | ||||
int flags; | |||||
all = downonly = uponly = namesonly = noload = verbose = 0; | all = downonly = uponly = namesonly = noload = verbose = 0; | ||||
f_inet = f_inet6 = f_ether = f_addr = NULL; | f_inet = f_inet6 = f_ether = f_addr = NULL; | ||||
envformat = getenv("IFCONFIG_FORMAT"); | envformat = getenv("IFCONFIG_FORMAT"); | ||||
if (envformat != NULL) | if (envformat != NULL) | ||||
setformat(envformat); | setformat(envformat); | ||||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | #endif | ||||
/* Check for address family */ | /* Check for address family */ | ||||
if (argc > 0) { | if (argc > 0) { | ||||
afp = af_getbyname(*argv); | afp = af_getbyname(*argv); | ||||
if (afp != NULL) | if (afp != NULL) | ||||
argc--, argv++; | argc--, argv++; | ||||
} | } | ||||
/* | |||||
* Check for a requested configuration action on a single interface, | |||||
* which doesn't require building, sorting, and searching the entire | |||||
* system address list | |||||
*/ | |||||
if ((argc > 0) && (ifname != NULL)) { | |||||
iflen = strlcpy(name, ifname, sizeof(name)); | |||||
if (iflen >= sizeof(name)) { | |||||
warnx("%s: interface name too long, skipping", ifname); | |||||
} else { | |||||
flags = getifflags(name, -1); | |||||
if (!(((flags & IFF_CANTCONFIG) != 0) || | |||||
(downonly && (flags & IFF_UP) != 0) || | |||||
(uponly && (flags & IFF_UP) == 0))) | |||||
ifconfig(argc, argv, 0, afp); | |||||
} | |||||
goto done; | |||||
} | |||||
if (getifaddrs(&ifap) != 0) | if (getifaddrs(&ifap) != 0) | ||||
err(EXIT_FAILURE, "getifaddrs"); | err(EXIT_FAILURE, "getifaddrs"); | ||||
cp = NULL; | cp = NULL; | ||||
if (calcorders(ifap, &q) != 0) | if (calcorders(ifap, &q) != 0) | ||||
err(EXIT_FAILURE, "calcorders"); | err(EXIT_FAILURE, "calcorders"); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | if (argc > 0) | ||||
ifconfig(argc, argv, 0, afp); | ifconfig(argc, argv, 0, afp); | ||||
else | else | ||||
status(afp, sdl, ifa); | status(afp, sdl, ifa); | ||||
} | } | ||||
if (namesonly) | if (namesonly) | ||||
printf("\n"); | printf("\n"); | ||||
freeifaddrs(ifap); | freeifaddrs(ifap); | ||||
done: | |||||
freeformat(); | freeformat(); | ||||
exit(exit_code); | exit(exit_code); | ||||
} | } | ||||
static struct afswtch *afs = NULL; | static struct afswtch *afs = NULL; | ||||
void | void | ||||
af_register(struct afswtch *p) | af_register(struct afswtch *p) | ||||
▲ Show 20 Lines • Show All 395 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
setifdstaddr(const char *addr, int param __unused, int s, | setifdstaddr(const char *addr, int param __unused, int s, | ||||
const struct afswtch *afp) | const struct afswtch *afp) | ||||
{ | { | ||||
if (afp->af_getaddr != NULL) | if (afp->af_getaddr != NULL) | ||||
afp->af_getaddr(addr, DSTADDR); | afp->af_getaddr(addr, DSTADDR); | ||||
} | } | ||||
static int | |||||
getifflags(const char *ifname, int us) | |||||
kp: This would probably be easier to follow if you added a name (or ifname) argument.
There's a… | |||||
Done Inline ActionsI could do that, although it wouldn't really change the balance of code using global state as this is just extracting existing code that uses the 'name' global int a function to avoid copy-pasting it. pkelsey: I could do that, although it wouldn't really change the balance of code using global state as… | |||||
{ | |||||
struct ifreq my_ifr; | |||||
int s; | |||||
memset(&my_ifr, 0, sizeof(my_ifr)); | |||||
(void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name)); | |||||
if (us < 0) { | |||||
if ((s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) | |||||
err(1, "socket(family AF_LOCAL,SOCK_DGRAM"); | |||||
} else | |||||
s = us; | |||||
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { | |||||
Perror("ioctl (SIOCGIFFLAGS)"); | |||||
Not Done Inline ActionsWould we get this error if the interface doesn't exist? kp: Would we get this error if the interface doesn't exist? | |||||
Done Inline ActionsIt appears that with the current kernel code, yes that is the failure case that could occur. It's also possible for an error to occur if this ioctl is invoked in a vnet that is not up and running yet, but it's not clear that case can be hit via running ifconfig. pkelsey: It appears that with the current kernel code, yes that is the failure case that could occur. | |||||
Not Done Inline ActionsRight, but without this patch 'ifconfig foo' results in 'ifconfig: interface foo does not exist', and I think we'd want to keep that behaviour. kp: Right, but without this patch 'ifconfig foo' results in 'ifconfig: interface foo does not… | |||||
Done Inline ActionsThat behavior is unchanged by this patch. pkelsey: That behavior is unchanged by this patch. | |||||
Not Done Inline ActionsDoesn't that mean that check on the name length in line 539 is redundant? If we've already checked that the interface (name) exists, it should be of an acceptable length. kp: Doesn't that mean that check on the name length in line 539 is redundant? If we've already… | |||||
Done Inline ActionsHmm, possibly. This was a straight extract of what is going on in the ifa processing loop below, so the corresponding check would be redundant there also I think based on the same underlying reasoning, which would be that the system never contains interface names longer than IFNAMSIZ. pkelsey: Hmm, possibly. This was a straight extract of what is going on in the ifa processing loop… | |||||
Done Inline ActionsSpecifically, 'ifconfig foo' resulting in 'ifconfig: interface foo does not exist' is due to if_nametoindex() returning 0. pkelsey: Specifically, 'ifconfig foo' resulting in 'ifconfig: interface foo does not exist' is due to… | |||||
exit(1); | |||||
} | |||||
if (us < 0) | |||||
close(s); | |||||
return ((my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16)); | |||||
} | |||||
/* | /* | ||||
* Note: doing an SIOCIGIFFLAGS scribbles on the union portion | * Note: doing an SIOCIGIFFLAGS scribbles on the union portion | ||||
* of the ifreq structure, which may confuse other parts of ifconfig. | * of the ifreq structure, which may confuse other parts of ifconfig. | ||||
* Make a private copy so we can avoid that. | * Make a private copy so we can avoid that. | ||||
*/ | */ | ||||
static void | static void | ||||
setifflags(const char *vname, int value, int s, const struct afswtch *afp) | setifflags(const char *vname, int value, int s, const struct afswtch *afp) | ||||
{ | { | ||||
struct ifreq my_ifr; | struct ifreq my_ifr; | ||||
int flags; | int flags; | ||||
memset(&my_ifr, 0, sizeof(my_ifr)); | flags = getifflags(name, s); | ||||
(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); | |||||
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { | |||||
Perror("ioctl (SIOCGIFFLAGS)"); | |||||
exit(1); | |||||
} | |||||
flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); | |||||
if (value < 0) { | if (value < 0) { | ||||
value = -value; | value = -value; | ||||
flags &= ~value; | flags &= ~value; | ||||
} else | } else | ||||
flags |= value; | flags |= value; | ||||
memset(&my_ifr, 0, sizeof(my_ifr)); | |||||
(void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); | |||||
my_ifr.ifr_flags = flags & 0xffff; | my_ifr.ifr_flags = flags & 0xffff; | ||||
my_ifr.ifr_flagshigh = flags >> 16; | my_ifr.ifr_flagshigh = flags >> 16; | ||||
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) | if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) | ||||
Perror(vname); | Perror(vname); | ||||
} | } | ||||
void | void | ||||
setifcap(const char *vname, int value, int s, const struct afswtch *afp) | setifcap(const char *vname, int value, int s, const struct afswtch *afp) | ||||
▲ Show 20 Lines • Show All 463 Lines • Show Last 20 Lines |
This would probably be easier to follow if you added a name (or ifname) argument.
There's a background project to try to lib-ify ifconfig, so anything that removes global state is helpful.