diff --git a/doc/ja/lxc.container.conf.sgml.in b/doc/ja/lxc.container.conf.sgml.in index b1d2ed517..aa363512b 100644 --- a/doc/ja/lxc.container.conf.sgml.in +++ b/doc/ja/lxc.container.conf.sgml.in @@ -1684,7 +1684,7 @@ by KATOH Yasufumi - + diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 3b68a91e0..d4581587a 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1201,7 +1201,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 4d28309fe..f27c4acea 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -4350,10 +4350,13 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key) bool all = false; const char *k = NULL; - if (strcmp(key, "lxc.limit") == 0) + if (strcmp(key, "lxc.limit") == 0 + || strcmp(key, "lxc.prlimit")) all = true; else if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) == 0) k = key + sizeof("lxc.limit.")-1; + else if (strncmp(key, "lxc.prlimit.", sizeof("lxc.prlimit.")-1) == 0) + k = key + sizeof("lxc.prlimit.")-1; else return -1; @@ -4515,7 +4518,7 @@ void lxc_conf_free(struct lxc_conf *conf) lxc_clear_includes(conf); lxc_clear_aliens(conf); lxc_clear_environment(conf); - lxc_clear_limits(conf, "lxc.limit"); + lxc_clear_limits(conf, "lxc.prlimit"); free(conf); } diff --git a/src/lxc/confile.c b/src/lxc/confile.c index a63b5e398..58a98e541 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -131,7 +131,7 @@ lxc_config_define(init_gid); lxc_config_define(ephemeral); lxc_config_define(syslog); lxc_config_define(no_new_privs); -lxc_config_define(limit); +lxc_config_define(prlimit); static struct lxc_config_t config[] = { { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, }, @@ -232,7 +232,13 @@ static struct lxc_config_t config[] = { { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, }, { "lxc.syslog", set_config_syslog, get_config_syslog, clr_config_syslog, }, { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, }, + + /* REMOVE IN LXC 3.0 + legacy keys + */ { "lxc.limit", set_config_limit, get_config_limit, clr_config_limit, }, + + { "lxc.prlimit", set_config_prlimit, get_config_prlimit, clr_config_prlimit, }, }; struct signame { @@ -1554,26 +1560,7 @@ out: return -1; } -static bool parse_limit_value(const char **value, unsigned long *res) -{ - char *endptr = NULL; - - if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) { - *res = RLIM_INFINITY; - *value += sizeof("unlimited") - 1; - return true; - } - - errno = 0; - *res = strtoul(*value, &endptr, 10); - if (errno || !endptr) - return false; - *value = endptr; - - return true; -} - -static int set_config_limit(const char *key, const char *value, +static int set_config_prlimit(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { struct lxc_list *iter; @@ -1585,10 +1572,10 @@ static int set_config_limit(const char *key, const char *value, if (lxc_config_value_empty(value)) return lxc_clear_limits(lxc_conf, key); - if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0) + if (strncmp(key, "lxc.prlimit.", sizeof("lxc.prlimit.") - 1) != 0) return -1; - key += sizeof("lxc.limit.") - 1; + key += sizeof("lxc.prlimit.") - 1; /* soft limit comes first in the value */ if (!parse_limit_value(&value, &limit_value)) @@ -3275,11 +3262,11 @@ static int get_config_no_new_privs(const char *key, char *retv, int inlen, } /* - * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value - * will be printed. If you ask for 'lxc.limit', then all limit entries will be - * printed, in 'lxc.limit.resource = value' format. + * If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value + * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be + * printed, in 'lxc.prlimit.resource = value' format. */ -static int get_config_limit(const char *key, char *retv, int inlen, +static int get_config_prlimit(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { int fulllen = 0, len; @@ -3291,10 +3278,10 @@ static int get_config_limit(const char *key, char *retv, int inlen, else memset(retv, 0, inlen); - if (!strcmp(key, "lxc.limit")) + if (!strcmp(key, "lxc.prlimit")) get_all = true; - else if (strncmp(key, "lxc.limit.", 10) == 0) - key += 10; + else if (strncmp(key, "lxc.prlimit.", 12) == 0) + key += 12; else return -1; @@ -3323,7 +3310,7 @@ static int get_config_limit(const char *key, char *retv, int inlen, } if (get_all) { - strprint(retv, inlen, "lxc.limit.%s = %s\n", + strprint(retv, inlen, "lxc.prlimit.%s = %s\n", lim->resource, buf); } else if (strcmp(lim->resource, key) == 0) { strprint(retv, inlen, "%s", buf); @@ -3628,7 +3615,7 @@ static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c, return 0; } -static inline int clr_config_limit(const char *key, struct lxc_conf *c, +static inline int clr_config_prlimit(const char *key, struct lxc_conf *c, void *data) { return lxc_clear_limits(c, key); diff --git a/src/lxc/confile_legacy.c b/src/lxc/confile_legacy.c index ba8bfe6ce..eee653db1 100644 --- a/src/lxc/confile_legacy.c +++ b/src/lxc/confile_legacy.c @@ -1079,3 +1079,159 @@ inline int clr_config_lsm_se_context(const char *key, struct lxc_conf *c, c->lsm_se_context = NULL; return 0; } + +extern int set_config_limit(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + struct lxc_list *iter; + struct rlimit limit; + unsigned long limit_value; + struct lxc_list *limlist = NULL; + struct lxc_limit *limelem = NULL; + + if (lxc_config_value_empty(value)) + return lxc_clear_limits(lxc_conf, key); + + if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0) + return -1; + + key += sizeof("lxc.limit.") - 1; + + /* soft limit comes first in the value */ + if (!parse_limit_value(&value, &limit_value)) + return -1; + limit.rlim_cur = limit_value; + + /* skip spaces and a colon */ + while (isspace(*value)) + ++value; + + if (*value == ':') + ++value; + else if (*value) /* any other character is an error here */ + return -1; + + while (isspace(*value)) + ++value; + + /* optional hard limit */ + if (*value) { + if (!parse_limit_value(&value, &limit_value)) + return -1; + limit.rlim_max = limit_value; + + /* check for trailing garbage */ + while (isspace(*value)) + ++value; + + if (*value) + return -1; + } else { + /* a single value sets both hard and soft limit */ + limit.rlim_max = limit.rlim_cur; + } + + /* find existing list element */ + lxc_list_for_each(iter, &lxc_conf->limits) + { + limelem = iter->elem; + if (!strcmp(key, limelem->resource)) { + limelem->limit = limit; + return 0; + } + } + + /* allocate list element */ + limlist = malloc(sizeof(*limlist)); + if (!limlist) + goto out; + + limelem = malloc(sizeof(*limelem)); + if (!limelem) + goto out; + memset(limelem, 0, sizeof(*limelem)); + + limelem->resource = strdup(key); + if (!limelem->resource) + goto out; + limelem->limit = limit; + + limlist->elem = limelem; + + lxc_list_add_tail(&lxc_conf->limits, limlist); + + return 0; + +out: + free(limlist); + if (limelem) { + free(limelem->resource); + free(limelem); + } + return -1; +} + +/* + * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value + * will be printed. If you ask for 'lxc.limit', then all limit entries will be + * printed, in 'lxc.limit.resource = value' format. + */ +extern int get_config_limit(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + int fulllen = 0, len; + bool get_all = false; + struct lxc_list *it; + + if (!retv) + inlen = 0; + else + memset(retv, 0, inlen); + + if (!strcmp(key, "lxc.limit")) + get_all = true; + else if (strncmp(key, "lxc.limit.", 10) == 0) + key += 10; + else + return -1; + + lxc_list_for_each(it, &c->limits) { + char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit + integers or the word + 'unlimited' */ + int partlen; + struct lxc_limit *lim = it->elem; + + if (lim->limit.rlim_cur == RLIM_INFINITY) { + memcpy(buf, "unlimited", sizeof("unlimited")); + partlen = sizeof("unlimited") - 1; + } else { + partlen = sprintf(buf, "%" PRIu64, + (uint64_t)lim->limit.rlim_cur); + } + if (lim->limit.rlim_cur != lim->limit.rlim_max) { + if (lim->limit.rlim_max == RLIM_INFINITY) { + memcpy(buf + partlen, ":unlimited", + sizeof(":unlimited")); + } else { + sprintf(buf + partlen, ":%" PRIu64, + (uint64_t)lim->limit.rlim_max); + } + } + + if (get_all) { + strprint(retv, inlen, "lxc.limit.%s = %s\n", + lim->resource, buf); + } else if (strcmp(lim->resource, key) == 0) { + strprint(retv, inlen, "%s", buf); + } + } + + return fulllen; +} + +extern int clr_config_limit(const char *key, struct lxc_conf *c, + void *data) +{ + return lxc_clear_limits(c, key); +} diff --git a/src/lxc/confile_legacy.h b/src/lxc/confile_legacy.h index 3b9fc60ea..ab64a0e8a 100644 --- a/src/lxc/confile_legacy.h +++ b/src/lxc/confile_legacy.h @@ -86,5 +86,6 @@ lxc_config_legacy_define(network_legacy); lxc_config_legacy_define(lsm_aa_profile); lxc_config_legacy_define(lsm_aa_incomplete); lxc_config_legacy_define(lsm_se_context); +lxc_config_legacy_define(limit); #endif /* __LXC_CONFILE_LEGACY_H */ diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c index b632d7b59..332b98ae8 100644 --- a/src/lxc/confile_utils.c +++ b/src/lxc/confile_utils.c @@ -661,3 +661,23 @@ int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v) return snprintf(retv, inlen, "%d", v); } + +bool parse_limit_value(const char **value, unsigned long *res) +{ + char *endptr = NULL; + + if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) { + *res = RLIM_INFINITY; + *value += sizeof("unlimited") - 1; + return true; + } + + errno = 0; + *res = strtoul(*value, &endptr, 10); + if (errno || !endptr) + return false; + *value = endptr; + + return true; +} + diff --git a/src/lxc/confile_utils.h b/src/lxc/confile_utils.h index bee53dd26..222de3de9 100644 --- a/src/lxc/confile_utils.h +++ b/src/lxc/confile_utils.h @@ -84,5 +84,5 @@ extern void update_hwaddr(const char *line); extern bool new_hwaddr(char *hwaddr); extern int lxc_get_conf_str(char *retv, int inlen, const char *value); extern int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v); - +extern bool parse_limit_value(const char **value, unsigned long *res); #endif /* __LXC_CONFILE_UTILS_H */ diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c index 3836a361c..3cf5a67ca 100644 --- a/src/tests/parse_config_file.c +++ b/src/tests/parse_config_file.c @@ -729,13 +729,22 @@ int main(int argc, char *argv[]) goto non_test_error; } - /* lxc.limit.nofile */ + /* REMOVE IN LXC 3.0 + legacy lxc.limit.* key + */ if (set_get_compare_clear_save_load(c, "lxc.limit.nofile", "65536", tmpf, true) < 0) { lxc_error("%s\n", "lxc.limit.nofile"); goto non_test_error; } + /* lxc.prlimit.nofile */ + if (set_get_compare_clear_save_load(c, "lxc.prlimit.nofile", "65536", + tmpf, true) < 0) { + lxc_error("%s\n", "lxc.prlimit.nofile"); + goto non_test_error; + } + if (test_idmap_parser() < 0) { lxc_error("%s\n", "failed to test parser for \"lxc.id_map\""); goto non_test_error;