diff options
author | Ulrich Drepper <drepper@redhat.com> | 2010-04-03 20:36:59 -0700 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2010-04-03 20:36:59 -0700 |
commit | b8b14c4cc38883032b8ebae50c9a8b3efd256483 (patch) | |
tree | 13cb6192d90590abb8171569f52921aa3ec51376 /sysdeps | |
parent | 3ed8e241229e370cca96650ed727f09838c51d67 (diff) | |
download | glibc-b8b14c4cc38883032b8ebae50c9a8b3efd256483.zip glibc-b8b14c4cc38883032b8ebae50c9a8b3efd256483.tar.gz glibc-b8b14c4cc38883032b8ebae50c9a8b3efd256483.tar.bz2 |
Fix changes to interface list during getifaddrs calls.
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/unix/sysv/linux/ifaddrs.c | 55 |
1 files changed, 43 insertions, 12 deletions
diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c index 149bd1c..84f223d 100644 --- a/sysdeps/unix/sysv/linux/ifaddrs.c +++ b/sysdeps/unix/sysv/linux/ifaddrs.c @@ -1,5 +1,5 @@ /* getifaddrs -- get names and addresses of all network interfaces - Copyright (C) 2003-2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2003-2008, 2009, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -315,17 +315,19 @@ map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max) else if (map[i] == index) return i; } - /* This should never be reached. If this will be reached, we have - a very big problem. */ - abort (); + + /* This means interfaces changed inbetween the reading of the + RTM_GETLINK and RTM_GETADDR information. We have to repeat + everything. */ + return -1; } /* Create a linked list of `struct ifaddrs' structures, one for each network interface on the host machine. If successful, store the list in *IFAP and return 0. On errors, return -1 and set `errno'. */ -int -getifaddrs (struct ifaddrs **ifap) +static int +getifaddrs_internal (struct ifaddrs **ifap) { struct netlink_handle nh = { 0, 0, 0, NULL, NULL }; struct netlink_res *nlp; @@ -481,6 +483,13 @@ getifaddrs (struct ifaddrs **ifap) kernel. */ ifa_index = map_newlink (ifim->ifi_index - 1, ifas, map_newlink_data, newlink); + if (__builtin_expect (ifa_index == -1, 0)) + { + try_again: + result = -EAGAIN; + free (ifas); + goto exit_free; + } ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags; while (RTA_OK (rta, rtasize)) @@ -565,9 +574,11 @@ getifaddrs (struct ifaddrs **ifap) that we have holes in the interface part of the list, but we always have already the interface for this address. */ ifa_index = newlink + newaddr_idx; - ifas[ifa_index].ifa.ifa_flags - = ifas[map_newlink (ifam->ifa_index - 1, ifas, - map_newlink_data, newlink)].ifa.ifa_flags; + int idx = map_newlink (ifam->ifa_index - 1, ifas, + map_newlink_data, newlink); + if (__builtin_expect (idx == -1, 0)) + goto try_again; + ifas[ifa_index].ifa.ifa_flags = ifas[idx].ifa.ifa_flags; if (ifa_index > 0) ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa; ++newaddr_idx; @@ -747,9 +758,13 @@ getifaddrs (struct ifaddrs **ifap) /* If we didn't get the interface name with the address, use the name from the interface entry. */ if (ifas[ifa_index].ifa.ifa_name == NULL) - ifas[ifa_index].ifa.ifa_name - = ifas[map_newlink (ifam->ifa_index - 1, ifas, - map_newlink_data, newlink)].ifa.ifa_name; + { + int idx = map_newlink (ifam->ifa_index - 1, ifas, + map_newlink_data, newlink); + if (__builtin_expect (idx == -1, 0)) + goto try_again; + ifas[ifa_index].ifa.ifa_name = ifas[idx].ifa.ifa_name; + } /* Calculate the netmask. */ if (ifas[ifa_index].ifa.ifa_addr @@ -826,6 +841,22 @@ getifaddrs (struct ifaddrs **ifap) return result; } + + +/* Create a linked list of `struct ifaddrs' structures, one for each + network interface on the host machine. If successful, store the + list in *IFAP and return 0. On errors, return -1 and set `errno'. */ +int +getifaddrs (struct ifaddrs **ifap) +{ + int res; + + do + res = getifaddrs_internal (ifap); + while (res == -EAGAIN); + + return res; +} libc_hidden_def (getifaddrs) |