Commit 9c88ff1f by S.Çağlar Onur Committed by Serge Hallyn

Eliminate duplicate entries from list_active_containers (v2)

list_active_containers parses /proc/net/unix which can contain multiple entries for the same container; 0000000000000000: 00000002 00000000 00010000 0001 01 273672 @/var/lib/lxc/6/command 0000000000000000: 00000002 00000000 00010000 0001 01 274395 @/var/lib/lxc/5/command 0000000000000000: 00000002 00000000 00010000 0001 01 273890 @/var/lib/lxc/4/command 0000000000000000: 00000002 00000000 00010000 0001 01 273141 @/var/lib/lxc/3/command 0000000000000000: 00000002 00000000 00010000 0001 01 273915 @/var/lib/lxc/2/command 0000000000000000: 00000002 00000000 00010000 0001 01 273683 @/var/lib/lxc/1/command 0000000000000000: 00000002 00000000 00010000 0001 01 273074 @/var/lib/lxc/0/command 0000000000000000: 00000002 00000000 00010000 0001 01 273931 @/var/lib/lxc/9/command 0000000000000000: 00000002 00000000 00010000 0001 01 273110 @/var/lib/lxc/8/command 0000000000000000: 00000002 00000000 00010000 0001 01 273390 @/var/lib/lxc/7/command 0000000000000000: 00000003 00000000 00000000 0001 03 275903 @/var/lib/lxc/8/command 0000000000000000: 00000003 00000000 00000000 0001 03 276043 @/var/lib/lxc/1/command 0000000000000000: 00000003 00000000 00000000 0001 03 273301 @/var/lib/lxc/0/command 0000000000000000: 00000003 00000000 00000000 0001 03 275650 @/var/lib/lxc/4/command On this system list_active_containers returns 14 containers while only 10 containers are running. Following patch; * Introduces array_contains function to do a binary search on given array, * Starts to sort arrays inside the add_to_clist and add_to_names functions, * Consumes array_contains in list_active_containers to eliminate duplicates, * Replaces the linear search code in lxcapi_get_interfaces with the new function. Changes since v1: * Do not load containers if a if a container list is not passed in * Fix possible memory leaks in lxcapi_get_ips and lxcapi_get_interfaces if realloc fails Signed-off-by: 's avatarS.Çağlar Onur <caglar@10ur.org> Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent 44f820e3
...@@ -1322,12 +1322,81 @@ out: ...@@ -1322,12 +1322,81 @@ out:
return false; return false;
} }
// used by qsort and bsearch functions for comparing names
static inline int string_cmp(char **first, char **second)
{
return strcmp(*first, *second);
}
// used by qsort and bsearch functions for comparing container names
static inline int container_cmp(struct lxc_container **first, struct lxc_container **second)
{
return strcmp((*first)->name, (*second)->name);
}
static bool add_to_array(char ***names, char *cname, int pos)
{
char **newnames = realloc(*names, (pos+1) * sizeof(char *));
if (!newnames) {
ERROR("Out of memory");
return false;
}
*names = newnames;
newnames[pos] = strdup(cname);
if (!newnames[pos])
return false;
// sort the arrray as we will use binary search on it
qsort(newnames, pos + 1, sizeof(char *), (int (*)(const void *,const void *))string_cmp);
return true;
}
static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos)
{
struct lxc_container **newlist = realloc(*list, (pos+1) * sizeof(struct lxc_container *));
if (!newlist) {
ERROR("Out of memory");
return false;
}
*list = newlist;
newlist[pos] = c;
// sort the arrray as we will use binary search on it
qsort(newlist, pos + 1, sizeof(struct lxc_container *), (int (*)(const void *,const void *))container_cmp);
return true;
}
static char** get_from_array(char ***names, char *cname, int size)
{
return (char **)bsearch(&cname, *names, size, sizeof(char *), (int (*)(const void *, const void *))string_cmp);
}
static bool array_contains(char ***names, char *cname, int size) {
if(get_from_array(names, cname, size) != NULL)
return true;
return false;
}
static bool remove_from_array(char ***names, char *cname, int size)
{
char **result = get_from_array(names, cname, size);
if (result != NULL) {
free(result);
return true;
}
return false;
}
static char** lxcapi_get_interfaces(struct lxc_container *c) static char** lxcapi_get_interfaces(struct lxc_container *c)
{ {
int count = 0, i; int i, count = 0;
bool found = false;
struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
char **interfaces = NULL, **temp; char **interfaces = NULL;
int old_netns = -1, new_netns = -1; int old_netns = -1, new_netns = -1;
if (!enter_to_ns(c, &old_netns, &new_netns)) if (!enter_to_ns(c, &old_netns, &new_netns))
...@@ -1341,51 +1410,41 @@ static char** lxcapi_get_interfaces(struct lxc_container *c) ...@@ -1341,51 +1410,41 @@ static char** lxcapi_get_interfaces(struct lxc_container *c)
/* Iterate through the interfaces */ /* Iterate through the interfaces */
for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) { for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
/* if (array_contains(&interfaces, tempIfAddr->ifa_name, count))
* WARNING: Following "for" loop does a linear search over the interfaces array continue;
* For the containers with lots of interfaces this may be problematic.
* I'm not expecting this to be the common usage but if it turns out to be
* than using binary search or a hash table could be more elegant solution.
*/
for (i = 0; i < count; i++) {
if (strcmp(interfaces[i], tempIfAddr->ifa_name) == 0) {
found = true;
break;
}
}
if (!found) { if(!add_to_array(&interfaces, tempIfAddr->ifa_name, count))
count += 1; goto err;
temp = realloc(interfaces, count * sizeof(*interfaces)); count++;
if (!temp) { }
count -= 1;
goto out;
}
interfaces = temp;
interfaces[count - 1] = strdup(tempIfAddr->ifa_name);
}
found = false;
}
out: out:
if (interfaceArray) if (interfaceArray)
freeifaddrs(interfaceArray); freeifaddrs(interfaceArray);
exit_from_ns(c, &old_netns, &new_netns);
exit_from_ns(c, &old_netns, &new_netns); /* Append NULL to the array */
if(interfaces)
interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count);
/* Append NULL to the array */ return interfaces;
interfaces = (char **)lxc_append_null_to_array((void **)interfaces, count);
return interfaces; err:
for(i=0;i<count;i++)
free(interfaces[i]);
free(interfaces);
interfaces = NULL;
goto out;
} }
static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope) static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
{ {
int count = 0; int i, count = 0;
struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL; struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
char addressOutputBuffer[INET6_ADDRSTRLEN]; char addressOutputBuffer[INET6_ADDRSTRLEN];
void *tempAddrPtr = NULL; void *tempAddrPtr = NULL;
char **addresses = NULL, **temp; char **addresses = NULL;
char *address = NULL; char *address = NULL;
int old_netns = -1, new_netns = -1; int old_netns = -1, new_netns = -1;
...@@ -1430,14 +1489,9 @@ static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* fam ...@@ -1430,14 +1489,9 @@ static char** lxcapi_get_ips(struct lxc_container *c, char* interface, char* fam
if (!address) if (!address)
continue; continue;
count += 1; if(!add_to_array(&addresses, address, count))
temp = realloc(addresses, count * sizeof(*addresses)); goto err;
if (!temp) { count++;
count--;
goto out;
}
addresses = temp;
addresses[count - 1] = strdup(address);
} }
out: out:
...@@ -1447,9 +1501,18 @@ out: ...@@ -1447,9 +1501,18 @@ out:
exit_from_ns(c, &old_netns, &new_netns); exit_from_ns(c, &old_netns, &new_netns);
/* Append NULL to the array */ /* Append NULL to the array */
addresses = (char **)lxc_append_null_to_array((void **)addresses, count); if(addresses)
addresses = (char **)lxc_append_null_to_array((void **)addresses, count);
return addresses; return addresses;
err:
for(i=0;i<count;i++)
free(addresses[i]);
free(addresses);
addresses = NULL;
goto out;
} }
static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen) static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen)
...@@ -2884,34 +2947,6 @@ int lxc_get_wait_states(const char **states) ...@@ -2884,34 +2947,6 @@ int lxc_get_wait_states(const char **states)
return MAX_STATE; return MAX_STATE;
} }
static bool add_to_names(char ***names, char *cname, int pos)
{
char **newnames = realloc(*names, (pos+1) * sizeof(char *));
if (!newnames) {
ERROR("Out of memory");
return false;
}
*names = newnames;
newnames[pos] = strdup(cname);
if (!newnames[pos])
return false;
return true;
}
static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos)
{
struct lxc_container **newlist = realloc(*list, (pos+1) * sizeof(struct lxc_container *));
if (!newlist) {
ERROR("Out of memory");
return false;
}
*list = newlist;
newlist[pos] = c;
return true;
}
/* /*
* These next two could probably be done smarter with reusing a common function * These next two could probably be done smarter with reusing a common function
* with different iterators and tests... * with different iterators and tests...
...@@ -2952,7 +2987,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta ...@@ -2952,7 +2987,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
continue; continue;
if (names) { if (names) {
if (!add_to_names(names, direntp->d_name, cfound)) if (!add_to_array(names, direntp->d_name, cfound))
goto free_bad; goto free_bad;
} }
cfound++; cfound++;
...@@ -2967,14 +3002,16 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta ...@@ -2967,14 +3002,16 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
INFO("Container %s:%s has a config but could not be loaded", INFO("Container %s:%s has a config but could not be loaded",
lxcpath, direntp->d_name); lxcpath, direntp->d_name);
if (names) if (names)
free((*names)[cfound--]); if(!remove_from_array(names, direntp->d_name, cfound--))
goto free_bad;
continue; continue;
} }
if (!lxcapi_is_defined(c)) { if (!lxcapi_is_defined(c)) {
INFO("Container %s:%s has a config but is not defined", INFO("Container %s:%s has a config but is not defined",
lxcpath, direntp->d_name); lxcpath, direntp->d_name);
if (names) if (names)
free((*names)[cfound--]); if(!remove_from_array(names, direntp->d_name, cfound--))
goto free_bad;
lxc_container_put(c); lxc_container_put(c);
continue; continue;
} }
...@@ -3013,6 +3050,7 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai ...@@ -3013,6 +3050,7 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai
int i, cfound = 0, nfound = 0; int i, cfound = 0, nfound = 0;
int lxcpath_len; int lxcpath_len;
char *line = NULL; char *line = NULL;
char **unique_names = NULL;
size_t len = 0; size_t len = 0;
struct lxc_container *c; struct lxc_container *c;
...@@ -3051,10 +3089,12 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai ...@@ -3051,10 +3089,12 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai
continue; continue;
*p2 = '\0'; *p2 = '\0';
if (names) { if (array_contains(&unique_names, p, nfound))
if (!add_to_names(names, p, nfound)) continue;
goto free_bad;
} if (!add_to_array(&unique_names, p, nfound))
goto free_bad;
cfound++; cfound++;
if (!cret) { if (!cret) {
...@@ -3066,8 +3106,10 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai ...@@ -3066,8 +3106,10 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai
if (!c) { if (!c) {
INFO("Container %s:%s is running but could not be loaded", INFO("Container %s:%s is running but could not be loaded",
lxcpath, p); lxcpath, p);
if (names) if (names) {
free((*names)[cfound--]); if(!remove_from_array(&unique_names, p, cfound--))
goto free_bad;
}
continue; continue;
} }
...@@ -3084,6 +3126,9 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai ...@@ -3084,6 +3126,9 @@ int list_active_containers(const char *lxcpath, char ***names, struct lxc_contai
nfound++; nfound++;
} }
if (names)
*names = unique_names;
process_lock(); process_lock();
fclose(f); fclose(f);
process_unlock(); process_unlock();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment