<variablelist>
<varlistentry>
<term>
- <option>lxc.limit.[limit name]</option>
+ <option>lxc.prlimit.[limit name]</option>
</term>
<listitem>
<para>
<variablelist>
<varlistentry>
<term>
- <option>lxc.limit.[limit name]</option>
+ <option>lxc.prlimit.[limit name]</option>
</term>
<listitem>
<para>
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;
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);
}
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, },
{ "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 {
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;
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))
}
/*
- * 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;
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;
}
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);
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);
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);
+}
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 */
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;
+}
+
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 */
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;