</variablelist>
</refsect2>
+ <refsect2>
+ <title>Proc</title>
+ <para>
+ Configure proc filesystem for the container.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>lxc.proc.[proc file name]</option>
+ </term>
+ <listitem>
+ <para>
+ Specify the proc file name to be set. The file name available
+ are those listed under /proc/PID/.
+ Example:
+ </para>
+ <programlisting>
+ lxc.proc.oom_score_adj = 10
+ </programlisting>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
<refsect2>
<title>Ephemeral</title>
<para>
return 0;
}
+int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
+{
+ struct lxc_list *it;
+ struct lxc_proc *elem;
+ char *tmp = NULL;
+ char filename[MAXPATHLEN] = {0};
+ int ret = 0;
+
+ lxc_list_for_each(it, procs) {
+ elem = it->elem;
+ tmp = lxc_string_replace(".", "/", elem->filename);
+ if (!tmp) {
+ ERROR("Failed to replace key %s", elem->filename);
+ return -1;
+ }
+
+ ret = snprintf(filename, sizeof(filename), "/proc/%d/%s", pid, tmp);
+ free(tmp);
+ if (ret < 0 || (size_t)ret >= sizeof(filename)) {
+ ERROR("Error setting up proc filesystem path");
+ return -1;
+ }
+
+ ret = lxc_write_to_file(filename, elem->value, strlen(elem->value), false);
+ if (ret < 0) {
+ ERROR("Failed to setup proc filesystem %s to %s", elem->filename, elem->value);
+ return -1;
+ }
+ }
+ return 0;
+}
+
static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct lxc_conf *lxc_conf_init(void)
lxc_list_init(&new->environment);
lxc_list_init(&new->limits);
lxc_list_init(&new->sysctls);
+ lxc_list_init(&new->procs);
for (i = 0; i < NUM_LXC_HOOKS; i++)
lxc_list_init(&new->hooks[i]);
lxc_list_init(&new->groups);
return 0;
}
+int lxc_clear_procs(struct lxc_conf *c, const char *key)
+{
+ struct lxc_list *it,*next;
+ bool all = false;
+ const char *k = NULL;
+
+ if (strcmp(key, "lxc.proc") == 0)
+ all = true;
+ else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0)
+ k = key + sizeof("lxc.proc.") - 1;
+ else
+ return -1;
+
+ lxc_list_for_each_safe(it, &c->procs, next) {
+ struct lxc_proc *proc = it->elem;
+ if (!all && strcmp(proc->filename, k) != 0)
+ continue;
+ lxc_list_del(it);
+ free(proc->filename);
+ free(proc->value);
+ free(proc);
+ free(it);
+ }
+
+ return 0;
+}
+
int lxc_clear_groups(struct lxc_conf *c)
{
struct lxc_list *it,*next;
lxc_clear_environment(conf);
lxc_clear_limits(conf, "lxc.prlimit");
lxc_clear_sysctls(conf, "lxc.sysctl");
+ lxc_clear_procs(conf, "lxc.proc");
free(conf->cgroup_meta.dir);
free(conf->cgroup_meta.controllers);
free(conf);
char *value;
};
+/*
+ * Defines a structure to configure proc filesystem at runtime.
+ * @filename : the proc filesystem will be configured without the "lxc.proc" prefix
+ * @value : the value to set
+ */
+struct lxc_proc {
+ char *filename;
+ char *value;
+};
+
/*
* id_map is an id map entry. Form in confile is:
* lxc.idmap = u 0 9800 100
/* sysctls */
struct lxc_list sysctls;
+
+ /* procs */
+ struct lxc_list procs;
};
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
extern int in_caplist(int cap, struct lxc_list *caps);
extern int setup_sysctl_parameters(struct lxc_list *sysctls);
extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
+extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid);
+extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
#endif /* __LXC_CONF_H */
lxc_config_define(tty_dir);
lxc_config_define(uts_name);
lxc_config_define(sysctl);
+lxc_config_define(proc);
static struct lxc_config_t config[] = {
/* REMOVE in LXC 3.0 */
{ "lxc.tty.max", false, set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
{ "lxc.uts.name", false, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
{ "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
+ { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
/* [START]: REMOVE IN LXC 3.0 */
{ "lxc.pts", true, set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
return -1;
}
+static int set_config_proc(const char *key, const char *value,
+ struct lxc_conf *lxc_conf, void *data)
+{
+ const char *subkey;
+ struct lxc_list *proclist = NULL;
+ struct lxc_proc *procelem = NULL;
+
+ if (lxc_config_value_empty(value))
+ return clr_config_proc(key, lxc_conf, NULL);
+
+ if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") -1) != 0)
+ return -1;
+
+ subkey = key + sizeof("lxc.proc.") - 1;
+ if (*subkey == '\0')
+ return -EINVAL;
+
+ proclist = malloc(sizeof(*proclist));
+ if (!proclist)
+ goto on_error;
+
+ procelem = malloc(sizeof(*procelem));
+ if (!procelem)
+ goto on_error;
+ memset(procelem, 0, sizeof(*procelem));
+
+ procelem->filename = strdup(subkey);
+ procelem->value = strdup(value);
+
+ if (!procelem->filename || !procelem->value)
+ goto on_error;
+
+ proclist->elem = procelem;
+
+ lxc_list_add_tail(&lxc_conf->procs, proclist);
+
+ return 0;
+
+on_error:
+ free(proclist);
+ if (procelem) {
+ free(procelem->filename);
+ free(procelem->value);
+ free(procelem);
+ }
+
+ return -1;
+}
+
static int set_config_idmaps(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
return fulllen;
}
+static int get_config_proc(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ struct lxc_list *it;
+ int len;
+ int fulllen = 0;
+ bool get_all = false;
+
+ if (!retv)
+ inlen = 0;
+ else
+ memset(retv, 0, inlen);
+
+ if (strcmp(key, "lxc.proc") == 0)
+ get_all = true;
+ else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0)
+ key += sizeof("lxc.proc.") - 1;
+ else
+ return -1;
+
+ lxc_list_for_each(it, &c->procs) {
+ struct lxc_proc *proc = it->elem;
+
+ if (get_all) {
+ strprint(retv, inlen, "lxc.proc.%s = %s\n",
+ proc->filename, proc->value);
+ } else if (strcmp(proc->filename, key) == 0) {
+ strprint(retv, inlen, "%s", proc->value);
+ }
+ }
+
+ return fulllen;
+}
+
static int get_config_noop(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
return lxc_clear_sysctls(c, key);
}
+static inline int clr_config_proc(const char *key, struct lxc_conf *c,
+ void *data)
+{
+ return lxc_clear_procs(c, key);
+}
+
static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
void *data)
{
goto out_delete_net;
}
+ if (!lxc_list_empty(&conf->procs)) {
+ ret = setup_proc_filesystem(&conf->procs, handler->pid);
+ if (ret < 0)
+ goto out_delete_net;
+ }
+
/* Tell the child to continue its initialization. We'll get
* LXC_SYNC_CGROUP when it is ready for us to setup cgroups.
*/
}
printf("lxc.sysctl returned %d %s\n", ret, v3);
+#define PROC_OOM_SCORE_ADJ "lxc.proc.oom_score_adj = 10\n"
+#define ALL_PROCS "lxc.proc.setgroups = allow\n" PROC_OOM_SCORE_ADJ
+
+ ret = c->get_config_item(c, "lxc.proc", v3, 2047);
+ if (ret != 0) {
+ fprintf(stderr, "%d: get_config_item(proc) returned %d\n", __LINE__, ret);
+ goto out;
+ }
+
+ if (!c->set_config_item(c, "lxc.proc.setgroups", "allow")) {
+ fprintf(stderr, "%d: failed to set lxc.proc.setgroups\n", __LINE__);
+ goto out;
+ }
+
+ ret = c->get_config_item(c, "lxc.proc.setgroups", v2, 255);
+ if (ret < 0) {
+ fprintf(stderr, "%d: get_config_item(lxc.proc.setgroups) returned %d\n", __LINE__, ret);
+ goto out;
+ }
+ if (strcmp(v2, "allow")) {
+ fprintf(stderr, "%d: lxc.proc.setgroups returned wrong value: %d %s not 10\n", __LINE__, ret, v2);
+ goto out;
+ }
+ printf("lxc.proc.setgroups returned %d %s\n", ret, v2);
+
+ if (!c->set_config_item(c, "lxc.proc.oom_score_adj", "10")) {
+ fprintf(stderr, "%d: failed to set lxc.proc.oom_score_adj\n", __LINE__);
+ goto out;
+ }
+
+ ret = c->get_config_item(c, "lxc.proc.oom_score_adj", v2, 255);
+ if (ret < 0) {
+ fprintf(stderr, "%d: get_config_item(lxc.proc.oom_score_adj) returned %d\n", __LINE__, ret);
+ goto out;
+ }
+ if (strcmp(v2, "10")) {
+ fprintf(stderr, "%d: lxc.proc.oom_score_adj returned wrong value: %d %s not 10\n", __LINE__, ret, v2);
+ goto out;
+ }
+ printf("lxc.proc.oom_score_adj returned %d %s\n", ret, v2);
+
+ ret = c->get_config_item(c, "lxc.proc", v3, 2047);
+ if (ret != sizeof(ALL_PROCS)-1) {
+ fprintf(stderr, "%d: get_config_item(proc) returned %d\n", __LINE__, ret);
+ goto out;
+ }
+ if (strcmp(v3, ALL_PROCS)) {
+ fprintf(stderr, "%d: lxc.proc returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(ALL_PROCS) - 1, ALL_PROCS);
+ goto out;
+ }
+ printf("lxc.proc returned %d %s\n", ret, v3);
+
+ if (!c->clear_config_item(c, "lxc.proc.setgroups")) {
+ fprintf(stderr, "%d: failed clearing lxc.proc.setgroups\n", __LINE__);
+ goto out;
+ }
+ ret = c->get_config_item(c, "lxc.proc", v3, 2047);
+ if (ret < 0) {
+ fprintf(stderr, "%d: get_config_item(proc) returned %d\n", __LINE__, ret);
+ goto out;
+ }
+ if (strcmp(v3, PROC_OOM_SCORE_ADJ)) {
+ fprintf(stderr, "%d: lxc.proc returned wrong value: %d %s not %d %s\n", __LINE__, ret, v3, (int)sizeof(PROC_OOM_SCORE_ADJ) - 1, PROC_OOM_SCORE_ADJ);
+ goto out;
+ }
+ printf("lxc.proc returned %d %s\n", ret, v3);
+
if (!c->set_config_item(c, "lxc.aa_profile", "unconfined")) {
fprintf(stderr, "%d: failed to set aa_profile\n", __LINE__);
goto out;
goto non_test_error;
}
+ /* lxc.proc */
+ if (set_get_compare_clear_save_load(c, "lxc.proc.oom_score_adj", "10", tmpf,
+ true) < 0) {
+ lxc_error("%s\n", "lxc.proc.oom_score_adj");
+ goto non_test_error;
+ }
+
/* REMOVE IN LXC 3.0
legacy lxc.limit.* key
*/