diff --git a/src/lxc/cmd/lxc_user_nic.c b/src/lxc/cmd/lxc_user_nic.c index 06f195a376..6ead30b643 100644 --- a/src/lxc/cmd/lxc_user_nic.c +++ b/src/lxc/cmd/lxc_user_nic.c @@ -233,10 +233,10 @@ struct alloted_s { struct alloted_s *next; }; -static struct alloted_s *append_alloted(struct alloted_s **head, char *name, - int n) +static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int n) { - struct alloted_s *cur, *al; + __do_free struct alloted_s *al = NULL; + struct alloted_s *cur; if (!head || !name) { /* Sanity check. Parameters should not be null. */ @@ -244,32 +244,29 @@ static struct alloted_s *append_alloted(struct alloted_s **head, char *name, return NULL; } - al = malloc(sizeof(struct alloted_s)); + al = zalloc(sizeof(struct alloted_s)); if (!al) { CMD_SYSERROR("Failed to allocate memory\n"); return NULL; } al->name = strdup(name); - if (!al->name) { - free(al); + if (!al->name) return NULL; - } al->allowed = n; al->next = NULL; - if (!*head) { + if (*head) { + cur = *head; + while (cur->next) + cur = cur->next; + cur->next = al; + } else { *head = al; - return al; } - cur = *head; - while (cur->next) - cur = cur->next; - cur->next = al; - - return al; + return move_ptr(al); } static void free_alloted(struct alloted_s **head) @@ -321,10 +318,10 @@ static int get_alloted(char *me, char *intype, char *link, if (ret != 4) continue; - if (strlen(name) == 0) + if (is_empty_string(name)) continue; - if (strcmp(name, me)) { + if (!strequal(name, me)) { if (name[0] != '@') continue; @@ -332,17 +329,17 @@ static int get_alloted(char *me, char *intype, char *link, continue; } - if (strcmp(type, intype)) + if (!strequal(type, intype)) continue; - if (strcmp(link, br)) + if (!strequal(link, br)) continue; - /* Found the user or group with the appropriate settings, - * therefore finish the search. What to do if there are more - * than one applicable lines? not specified in the docs. Since - * getline is implemented with realloc, we don't need to free - * line until exiting func. + /* + * Found the user or group with the appropriate settings, + * therefore finish the search. What to do if there are is more + * than one applicable line? Currently this is not specified in + * the docs. * * If append_alloted returns NULL, e.g. due to a malloc error, * we set count to 0 and break the loop, allowing cleanup and diff --git a/src/lxc/confile.c b/src/lxc/confile.c index dbb7e3b010..a07572dc5b 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -95,6 +95,7 @@ lxc_config_define(init_cwd); lxc_config_define(init_gid); lxc_config_define(init_uid); lxc_config_define(init_groups); +lxc_config_define(jump_table_net); lxc_config_define(keyring_session); lxc_config_define(log_file); lxc_config_define(log_level); @@ -123,7 +124,6 @@ lxc_config_define(net_ipvlan_mode); lxc_config_define(net_ipvlan_isolation); lxc_config_define(net_mtu); lxc_config_define(net_name); -lxc_config_define(net_nic); lxc_config_define(net_script_down); lxc_config_define(net_script_up); lxc_config_define(net_type); @@ -227,9 +227,9 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.namespace.clone", true, set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, }, { "lxc.namespace.keep", true, set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, }, { "lxc.namespace.share", true, set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, }, - { "lxc.time.offset.boot", true, set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, }, + { "lxc.time.offset.boot", true, set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, }, { "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, }, - { "lxc.net.", false, set_config_net_nic, get_config_net_nic, clr_config_net_nic, }, + { "lxc.net.", false, set_config_jump_table_net, get_config_jump_table_net, clr_config_jump_table_net, }, { "lxc.net", true, set_config_net, get_config_net, clr_config_net, }, { "lxc.no_new_privs", true, set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, }, { "lxc.prlimit", false, set_config_prlimit, get_config_prlimit, clr_config_prlimit, }, @@ -257,7 +257,11 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, }, }; -static struct lxc_config_t config_jump_table_net[] = { +struct lxc_config_net_t { + LXC_CONFIG_MEMBERS; +}; + +static struct lxc_config_net_t config_jump_table_net[] = { /* If a longer key is added please update. */ #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2) { "flags", true, set_config_net_flags, get_config_net_flags, clr_config_net_flags, }, @@ -318,12 +322,20 @@ struct lxc_config_t *lxc_get_config(const char *key) return NULL; } -static struct lxc_config_t *lxc_get_config_net(const char *key) +static inline bool match_config_net_item(const struct lxc_config_net_t *entry, + const char *key) +{ + if (entry->strict) + return strequal(entry->name, key); + return strnequal(entry->name, key, strlen(entry->name)); +} + +static struct lxc_config_net_t *lxc_get_config_net(const char *key) { for (size_t i = 0; i < ARRAY_SIZE(config_jump_table_net); i++) { - struct lxc_config_t *cur = &config_jump_table_net[i]; + struct lxc_config_net_t *cur = &config_jump_table_net[i]; - if (!match_config_item(cur, key)) + if (!match_config_net_item(cur, key)) continue; return cur; @@ -5204,97 +5216,94 @@ static int get_config_includefiles(const char *key, char *retv, int inlen, return ret_errno(ENOSYS); } -static struct lxc_config_t *get_network_config_ops(const char *key, - struct lxc_conf *lxc_conf, - ssize_t *idx, - const char **const subkey) +struct config_net_info { + char buf[NETWORK_SUBKEY_SIZE_MAX]; + const char *subkey; + const struct lxc_config_net_t *ops; + struct lxc_netdev *netdev; +}; + +static int get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, + struct config_net_info *info, bool allocate) { - struct lxc_config_t *config = NULL; int ret; int64_t tmpidx; - const char *idx_start, *subkey_start; - char buf[NETWORK_SUBKEY_SIZE_MAX]; - - if (!idx) - return ret_set_errno(NULL, EINVAL); + unsigned int idx; + const char *idx_start; if (is_empty_string(key)) - return ret_set_errno(NULL, EINVAL); + return ret_errno(EINVAL); /* check that this is a sensible network key */ if (!strnequal("lxc.net.", key, STRLITERALLEN("lxc.net."))) - return log_error_errno(NULL, EINVAL, "Invalid network configuration key \"%s\"", key); + return syserror_set(-EINVAL, "Invalid network configuration key \"%s\"", key); /* lxc.net. */ /* beginning of index string */ idx_start = key + STRLITERALLEN("lxc.net."); if (!isdigit(*idx_start)) - return log_error_errno(NULL, EINVAL, "Failed to detect digit in string \"%s\"", key + 8); + return syserror_set(-EINVAL, "Failed to detect digit in string \"%s\"", key + 8); - ret = lxc_safe_int64_residual(idx_start, &tmpidx, 10, buf, sizeof(buf)); + ret = lxc_safe_int64_residual(idx_start, &tmpidx, 10, info->buf, sizeof(info->buf)); if (ret) - return log_error_errno(NULL, -ret, "Failed to parse network index"); + return syserror("Failed to parse network index"); if (tmpidx < 0 || tmpidx >= INT_MAX) - return log_error_errno(NULL, ERANGE, "Number of configured networks would overflow the counter"); - *idx = (ssize_t)tmpidx; + return syserror_set(-ERANGE, "Number of configured networks would overflow the counter"); + idx = (unsigned int)tmpidx; - if (!subkey) - return NULL; + info->netdev = lxc_get_netdev_by_idx(lxc_conf, idx, allocate); + if (!info->netdev) + return ret_errno(EINVAL); + + /* Make sure subkey points to the empty string. */ + info->subkey = info->buf; + if (is_empty_string(info->subkey)) + return ret_errno(ENOENT); - subkey_start = &buf[1]; - if (is_empty_string(subkey_start)) - return log_error_errno(NULL, EINVAL, "No network subkey specified"); + if (info->subkey[0] != '.') + return syserror_set(-EINVAL, "Invalid subkey"); + info->subkey++; /* lxc.net.. */ - *subkey = subkey_start; - config = lxc_get_config_net(*subkey); - if (!config) - return log_error_errno(NULL, ENOENT, "Unknown network configuration key \"%s\"", key); + info->ops = lxc_get_config_net(info->subkey); + if (!info->ops) + return syserror_set(-ENOENT, "Unknown network configuration key \"%s\"", key); - return config; + return 0; } /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was * found. So we make sure next comes an integer, find the right callback (by * rewriting the key), and call it. */ -static int set_config_net_nic(const char *key, const char *value, - struct lxc_conf *lxc_conf, void *data) +static int set_config_jump_table_net(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) { - const char *subkey = NULL; - ssize_t idx = -1; + struct config_net_info info = {}; + int ret; const char *idxstring; - struct lxc_config_t *config; - struct lxc_netdev *netdev; idxstring = key + STRLITERALLEN("lxc.net."); if (!isdigit(*idxstring)) return ret_errno(EINVAL); if (lxc_config_value_empty(value)) - return clr_config_net_nic(key, lxc_conf, data); - - config = get_network_config_ops(key, lxc_conf, &idx, &subkey); - if (!config || idx < 0) - return -errno; + return clr_config_jump_table_net(key, lxc_conf, data); - netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true); - if (!netdev) - return ret_errno(EINVAL); + ret = get_network_config_ops(key, lxc_conf, &info, true); + if (ret) + return ret; - return config->set(subkey, value, lxc_conf, netdev); + return info.ops->set(info.subkey, value, lxc_conf, info.netdev); } -static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf, - void *data) +static int clr_config_jump_table_net(const char *key, struct lxc_conf *lxc_conf, + void *data) { - const char *subkey = NULL; - ssize_t idx = -1; + struct config_net_info info = {}; int ret; const char *idxstring; - struct lxc_config_t *config; - struct lxc_netdev *netdev; idxstring = key + 8; if (!isdigit(*idxstring)) @@ -5317,15 +5326,11 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf, return 0; } - config = get_network_config_ops(key, lxc_conf, &idx, &subkey); - if (!config || idx < 0) - return -errno; - - netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false); - if (!netdev) - return ret_errno(EINVAL); + ret = get_network_config_ops(key, lxc_conf, &info, false); + if (ret) + return ret; - return config->clr(subkey, lxc_conf, netdev); + return info.ops->clr(info.subkey, lxc_conf, info.netdev); } static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf, @@ -5683,28 +5688,22 @@ static int clr_config_net_veth_ipv6_route(const char *key, return 0; } -static int get_config_net_nic(const char *key, char *retv, int inlen, - struct lxc_conf *c, void *data) +static int get_config_jump_table_net(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) { - const char *subkey = NULL; - ssize_t idx = -1; + struct config_net_info info = {}; + int ret; const char *idxstring; - struct lxc_config_t *config; - struct lxc_netdev *netdev; idxstring = key + STRLITERALLEN("lxc.net."); if (!isdigit(*idxstring)) return ret_errno(EINVAL); - config = get_network_config_ops(key, c, &idx, &subkey); - if (!config || idx < 0) - return -errno; - - netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false); - if (!netdev) - return ret_errno(EINVAL); + ret = get_network_config_ops(key, c, &info, false); + if (ret) + return ret; - return config->get(subkey, retv, inlen, c, netdev); + return info.ops->get(info.subkey, retv, inlen, c, info.netdev); } static int get_config_net_type(const char *key, char *retv, int inlen, @@ -6427,23 +6426,22 @@ int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv, int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen) { - int len; - const char *idxstring; + struct config_net_info info = {}; struct lxc_netdev *netdev; + int len, ret; + const char *idxstring; int fulllen = 0; - ssize_t idx = -1; idxstring = key + STRLITERALLEN("lxc.net."); if (!isdigit(*idxstring)) return ret_errno(EINVAL); - (void)get_network_config_ops(key, c, &idx, NULL); - if (idx < 0) - return ret_errno(EINVAL); - - netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false); - if (!netdev) - return ret_errno(EINVAL); + ret = get_network_config_ops(key, c, &info, false); + if (ret) { + if (ret != -ENOENT) + return ret_errno(EINVAL); + } + netdev = info.netdev; if (!retv) inlen = 0; diff --git a/src/lxc/confile.h b/src/lxc/confile.h index b04252b8f7..c49dc87228 100644 --- a/src/lxc/confile.h +++ b/src/lxc/confile.h @@ -32,12 +32,15 @@ typedef int (*config_get_cb)(const char *key, char *value, int inlen, typedef int (*config_clr_cb)(const char *key, struct lxc_conf *conf, void *data); +#define LXC_CONFIG_MEMBERS \ + char *name; \ + bool strict; \ + config_set_cb set; \ + config_get_cb get; \ + config_clr_cb clr + struct lxc_config_t { - char *name; - bool strict; - config_set_cb set; - config_get_cb get; - config_clr_cb clr; + LXC_CONFIG_MEMBERS; }; struct new_config_item { diff --git a/src/lxc/string_utils.c b/src/lxc/string_utils.c index 18c64c11ef..366cbd9ed9 100644 --- a/src/lxc/string_utils.c +++ b/src/lxc/string_utils.c @@ -192,41 +192,6 @@ char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix) return result; } -char **lxc_normalize_path(const char *path) -{ - char **components; - size_t components_len = 0; - size_t pos = 0; - - components = lxc_string_split(path, '/'); - if (!components) - return NULL; - - /* resolve '.' and '..' */ - for (pos = 0; pos < components_len;) { - if (strequal(components[pos], ".") || - (strequal(components[pos], "..") && pos == 0)) { - /* eat this element */ - free(components[pos]); - memmove(&components[pos], &components[pos + 1], - sizeof(char *) * (components_len - pos)); - components_len--; - } else if (strequal(components[pos], "..")) { - /* eat this and the previous element */ - free(components[pos - 1]); - free(components[pos]); - memmove(&components[pos - 1], &components[pos + 1], - sizeof(char *) * (components_len - pos)); - components_len -= 2; - pos--; - } else { - pos++; - } - } - - return components; -} - /* taken from systemd */ char *path_simplify(const char *path) { @@ -672,8 +637,9 @@ int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base) return 0; } -int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, char *residual, - size_t residual_len) +int lxc_safe_int64_residual(const char *restrict numstr, + int64_t *restrict converted, int base, + char *restrict residual, size_t residual_len) { char *remaining = NULL; int64_t u; @@ -692,7 +658,7 @@ int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, ch errno = 0; u = strtoll(numstr, &remaining, base); if (errno == ERANGE && u == INT64_MAX) - return -ERANGE; + return ret_errno(ERANGE); if (remaining == numstr) return -EINVAL; @@ -705,11 +671,11 @@ int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, ch len = strlen(remaining); if (len >= residual_len) - return -EINVAL; + return ret_errno(EINVAL); memcpy(residual, remaining, len); } else if (*remaining != '\0') { - return -EINVAL; + return ret_errno(EINVAL); } out: diff --git a/src/lxc/string_utils.h b/src/lxc/string_utils.h index 1bea9a01cd..44f2f3e1e9 100644 --- a/src/lxc/string_utils.h +++ b/src/lxc/string_utils.h @@ -30,21 +30,7 @@ __hidden extern char *lxc_string_replace(const char *needle, const char *replace const char *haystack); __hidden extern bool lxc_string_in_array(const char *needle, const char **haystack); __hidden extern char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix); -/* - * Normalize and split path: Leading and trailing / are removed, multiple - * / are compactified, .. and . are resolved (.. on the top level is considered - * identical to .). - * Examples: - * / -> { NULL } - * foo/../bar -> { bar, NULL } - * ../../ -> { NULL } - * ./bar/baz/.. -> { bar, NULL } - * foo//bar -> { foo, bar, NULL } - */ -__hidden extern char **lxc_normalize_path(const char *path); -/* remove multiple slashes from the path, e.g. ///foo//bar -> /foo/bar */ -__hidden extern char *lxc_deslashify(const char *path); __hidden extern char *lxc_append_paths(const char *first, const char *second); /* @@ -78,8 +64,10 @@ __hidden extern int lxc_safe_long(const char *numstr, long int *converted); __hidden extern int lxc_safe_long_long(const char *numstr, long long int *converted); __hidden extern int lxc_safe_ulong(const char *numstr, unsigned long *converted); __hidden extern int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base); -__hidden extern int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, - char *residual, size_t residual_len); +__hidden extern int lxc_safe_int64_residual(const char *restrict numstr, + int64_t *restrict converted, + int base, char *restrict residual, + size_t residual_len); /* Handles B, kb, MB, GB. Detects overflows and reports -ERANGE. */ __hidden extern int parse_byte_size_string(const char *s, long long int *converted); diff --git a/src/lxc/tools/lxc_copy.c b/src/lxc/tools/lxc_copy.c index c406929272..a786a300c5 100644 --- a/src/lxc/tools/lxc_copy.c +++ b/src/lxc/tools/lxc_copy.c @@ -289,6 +289,41 @@ static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_argu return 0; } +static char **lxc_normalize_path(const char *path) +{ + char **components; + size_t components_len = 0; + size_t pos = 0; + + components = lxc_string_split(path, '/'); + if (!components) + return NULL; + + /* resolve '.' and '..' */ + for (pos = 0; pos < components_len;) { + if (strequal(components[pos], ".") || + (strequal(components[pos], "..") && pos == 0)) { + /* eat this element */ + free(components[pos]); + memmove(&components[pos], &components[pos + 1], + sizeof(char *) * (components_len - pos)); + components_len--; + } else if (strequal(components[pos], "..")) { + /* eat this and the previous element */ + free(components[pos - 1]); + free(components[pos]); + memmove(&components[pos - 1], &components[pos + 1], + sizeof(char *) * (components_len - pos)); + components_len -= 2; + pos--; + } else { + pos++; + } + } + + return components; +} + static char *construct_path(char *path, bool as_prefix) { char **components = NULL;