confile.c revision 508c263ee6ed2fac73f6979af287caba38963b4b
/*
* lxc: linux Container library
*
* (C) Copyright IBM Corp. 2007, 2008
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include "parse.h"
#include "config.h"
#include "confile.h"
#include "utils.h"
#include "log.h"
#include "conf.h"
#include "network.h"
#include <sys/personality.h>
#endif
static int config_personality(const char *, const char *, struct lxc_conf *);
static int config_pts(const char *, const char *, struct lxc_conf *);
static int config_tty(const char *, const char *, struct lxc_conf *);
static int config_ttydir(const char *, const char *, struct lxc_conf *);
static int config_kmsg(const char *, const char *, struct lxc_conf *);
static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
static int config_lsm_se_context(const char *, const char *, struct lxc_conf *);
static int config_cgroup(const char *, const char *, struct lxc_conf *);
static int config_idmap(const char *, const char *, struct lxc_conf *);
static int config_loglevel(const char *, const char *, struct lxc_conf *);
static int config_logfile(const char *, const char *, struct lxc_conf *);
static int config_mount(const char *, const char *, struct lxc_conf *);
static int config_rootfs(const char *, const char *, struct lxc_conf *);
static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
static int config_pivotdir(const char *, const char *, struct lxc_conf *);
static int config_utsname(const char *, const char *, struct lxc_conf *);
static int config_network_type(const char *, const char *, struct lxc_conf *);
static int config_network_flags(const char *, const char *, struct lxc_conf *);
static int config_network_link(const char *, const char *, struct lxc_conf *);
static int config_network_name(const char *, const char *, struct lxc_conf *);
static int config_network_veth_pair(const char *, const char *, struct lxc_conf *);
static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
static int config_network_hwaddr(const char *, const char *, struct lxc_conf *);
static int config_network_vlan_id(const char *, const char *, struct lxc_conf *);
static int config_network_mtu(const char *, const char *, struct lxc_conf *);
static int config_network_ipv4(const char *, const char *, struct lxc_conf *);
static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
static int config_network_script_up(const char *, const char *, struct lxc_conf *);
static int config_network_script_down(const char *, const char *, struct lxc_conf *);
static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
static int config_cap_drop(const char *, const char *, struct lxc_conf *);
static int config_cap_keep(const char *, const char *, struct lxc_conf *);
static int config_console(const char *, const char *, struct lxc_conf *);
static int config_seccomp(const char *, const char *, struct lxc_conf *);
static int config_includefile(const char *, const char *, struct lxc_conf *);
static int config_network_nic(const char *, const char *, struct lxc_conf *);
static int config_autodev(const char *, const char *, struct lxc_conf *);
static int config_haltsignal(const char *, const char *, struct lxc_conf *);
static int config_stopsignal(const char *, const char *, struct lxc_conf *);
static int config_start(const char *, const char *, struct lxc_conf *);
static int config_group(const char *, const char *, struct lxc_conf *);
static struct lxc_config_t config[] = {
{ "lxc.arch", config_personality },
{ "lxc.pts", config_pts },
{ "lxc.tty", config_tty },
{ "lxc.devttydir", config_ttydir },
{ "lxc.kmsg", config_kmsg },
{ "lxc.aa_profile", config_lsm_aa_profile },
{ "lxc.se_context", config_lsm_se_context },
{ "lxc.cgroup", config_cgroup },
{ "lxc.id_map", config_idmap },
{ "lxc.loglevel", config_loglevel },
{ "lxc.logfile", config_logfile },
{ "lxc.mount", config_mount },
{ "lxc.rootfs.mount", config_rootfs_mount },
{ "lxc.rootfs", config_rootfs },
{ "lxc.pivotdir", config_pivotdir },
{ "lxc.utsname", config_utsname },
{ "lxc.hook.pre-start", config_hook },
{ "lxc.hook.pre-mount", config_hook },
{ "lxc.hook.mount", config_hook },
{ "lxc.hook.autodev", config_hook },
{ "lxc.hook.start", config_hook },
{ "lxc.hook.post-stop", config_hook },
{ "lxc.hook.clone", config_hook },
{ "lxc.network.type", config_network_type },
{ "lxc.network.flags", config_network_flags },
{ "lxc.network.link", config_network_link },
{ "lxc.network.name", config_network_name },
{ "lxc.network.macvlan.mode", config_network_macvlan_mode },
{ "lxc.network.veth.pair", config_network_veth_pair },
{ "lxc.network.script.up", config_network_script_up },
{ "lxc.network.script.down", config_network_script_down },
{ "lxc.network.hwaddr", config_network_hwaddr },
{ "lxc.network.mtu", config_network_mtu },
{ "lxc.network.vlan.id", config_network_vlan_id },
{ "lxc.network.ipv4.gateway", config_network_ipv4_gateway },
{ "lxc.network.ipv4", config_network_ipv4 },
{ "lxc.network.ipv6.gateway", config_network_ipv6_gateway },
{ "lxc.network.ipv6", config_network_ipv6 },
/* config_network_nic must come after all other 'lxc.network.*' entries */
{ "lxc.network.", config_network_nic },
{ "lxc.cap.drop", config_cap_drop },
{ "lxc.cap.keep", config_cap_keep },
{ "lxc.console", config_console },
{ "lxc.seccomp", config_seccomp },
{ "lxc.include", config_includefile },
{ "lxc.autodev", config_autodev },
{ "lxc.haltsignal", config_haltsignal },
{ "lxc.stopsignal", config_stopsignal },
{ "lxc.start.auto", config_start },
{ "lxc.start.delay", config_start },
{ "lxc.start.order", config_start },
{ "lxc.group", config_group },
};
struct signame {
int num;
const char *name;
};
{ SIGHUP, "HUP" },
{ SIGINT, "INT" },
{ SIGQUIT, "QUIT" },
{ SIGILL, "ILL" },
{ SIGABRT, "ABRT" },
{ SIGFPE, "FPE" },
{ SIGKILL, "KILL" },
{ SIGSEGV, "SEGV" },
{ SIGPIPE, "PIPE" },
{ SIGALRM, "ALRM" },
{ SIGTERM, "TERM" },
{ SIGUSR1, "USR1" },
{ SIGUSR2, "USR2" },
{ SIGCHLD, "CHLD" },
{ SIGCONT, "CONT" },
{ SIGSTOP, "STOP" },
{ SIGTSTP, "TSTP" },
{ SIGTTIN, "TTIN" },
{ SIGTTOU, "TTOU" },
};
{
int i;
for (i = 0; i < config_size; i++)
return &config[i];
return NULL;
}
do { \
if (inlen > 0) { \
} \
} while (0);
{
if (!retv)
inlen = 0;
else
for (i = 0; i < config_size; i++) {
continue;
}
return fulllen;
}
{
char *new_value;
if (*conf_item)
return 0;
}
if (!new_value) {
return -1;
}
if (*conf_item)
return 0;
}
{
return -1;
}
}
{
}
/*
* config entry is something like "lxc.network.0.ipv4"
* the key 'lxc.network.' was found. So we make sure next
* comes an integer, find the right callback (by rewriting
* the key), and call it.
*/
{
int ret = -1;
struct lxc_config_t *config;
if (!copy) {
SYSERROR("failed to allocate memory");
return -1;
}
/*
* ok we know that to get here we've got "lxc.network."
* and it isn't any of the other network entries. So
* after the second . should come an integer (# of defined
* nic) followed by a valid entry.
*/
goto out;
if (!p)
goto out;
if (!config) {
goto out;
}
out:
return ret;
}
{
struct lxc_netdev *netdev;
return lxc_clear_config_network(lxc_conf);
if (!netdev) {
SYSERROR("failed to allocate memory");
return -1;
}
if (!list) {
SYSERROR("failed to allocate memory");
return -1;
}
else {
return -1;
}
return 0;
}
{
return 32 - IN_CLASSA_NSHIFT;
return 32 - IN_CLASSB_NSHIFT;
return 32 - IN_CLASSC_NSHIFT;
return 0;
}
/*
* if you have p="lxc.network.0.link", pass it p+12
* to get back '0' (the index of the nic)
*/
static int get_network_netdev_idx(const char *key)
{
return -1;
if (ret != 1)
return -1;
return idx;
}
/*
* if you have p="lxc.network.0", pass this p+12 and it will return
* the netdev of the first configured nic
*/
{
if (idx == -1)
return NULL;
if (idx == i++) {
break;
}
}
return netdev;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
if (!retv)
inlen = 0;
else
}
case LXC_NET_VETH:
break;
case LXC_NET_MACVLAN:
break;
case LXC_NET_VLAN:
break;
case LXC_NET_PHYS:
break;
}
return fulllen;
}
{
if (lxc_list_empty(network)) {
ERROR("network is not created for '%s' = '%s' option",
return NULL;
}
else
if (!netdev) {
ERROR("no network device defined for '%s' = '%s' option",
return NULL;
}
return netdev;
}
{
}
#ifndef MACVLAN_MODE_PRIVATE
# define MACVLAN_MODE_PRIVATE 1
#endif
#ifndef MACVLAN_MODE_VEPA
# define MACVLAN_MODE_VEPA 2
#endif
#ifndef MACVLAN_MODE_BRIDGE
# define MACVLAN_MODE_BRIDGE 4
#endif
{
struct mc_mode {
char *name;
int mode;
} m[] = {
{ "private", MACVLAN_MODE_PRIVATE },
{ "vepa", MACVLAN_MODE_VEPA },
{ "bridge", MACVLAN_MODE_BRIDGE },
};
int i;
for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
continue;
return 0;
}
return -1;
}
static int rand_complete_hwaddr(char *hwaddr)
{
const char hex[] = "0123456789abcdef";
#ifndef HAVE_RAND_R
randseed(true);
#else
#endif
while (*curs != '\0')
{
//ensure address is unicast
#ifdef HAVE_RAND_R
} else {
#else
} else {
#endif
}
}
curs++;
}
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
if (!new_value) {
return -1;
}
if (!netdev) {
return -1;
};
return 0;
}
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
return -1;
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
struct lxc_inetdev *inetdev;
if (!netdev)
return -1;
if (!inetdev) {
SYSERROR("failed to allocate ipv4 address");
return -1;
}
if (!list) {
SYSERROR("failed to allocate memory");
return -1;
}
if (!addr) {
ERROR("no address specified");
return -1;
}
if (cursor) {
*cursor = '\0';
}
if (slash) {
*slash = '\0';
}
return -1;
}
return -1;
}
/* no prefix specified, determine it from the network class */
/* if no broadcast address, let compute one from the
* prefix and address
*/
if (!bcast) {
}
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
if (!gw) {
SYSERROR("failed to allocate ipv4 gateway address");
return -1;
}
if (!value) {
ERROR("no ipv4 gateway address specified");
return -1;
}
netdev->ipv4_gateway_auto = true;
} else {
return -1;
}
netdev->ipv4_gateway_auto = false;
}
return 0;
}
{
struct lxc_netdev *netdev;
struct lxc_inet6dev *inet6dev;
char *netmask;
if (!netdev)
return -1;
if (!inet6dev) {
SYSERROR("failed to allocate ipv6 address");
return -1;
}
if (!list) {
SYSERROR("failed to allocate memory");
return -1;
}
if (!valdup) {
ERROR("no address specified");
return -1;
}
if (slash) {
*slash = '\0';
}
return -1;
}
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
if (!value) {
ERROR("no ipv6 gateway address specified");
return -1;
}
netdev->ipv6_gateway_auto = true;
} else {
if (!gw) {
SYSERROR("failed to allocate ipv6 gateway address");
return -1;
}
return -1;
}
netdev->ipv6_gateway_auto = false;
}
return 0;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
struct lxc_netdev *netdev;
if (!netdev)
return -1;
}
{
if (!hooklist) {
return -1;
}
return 0;
}
{
}
{
char *copy;
if (!copy) {
return -1;
}
return -1;
}
{
if (personality >= 0)
else
return 0;
}
{
return 0;
}
{
return 0;
}
return 0;
}
return 0;
}
return -1;
}
{
int ret = -1;
return lxc_clear_groups(lxc_conf);
if (!groups) {
return -1;
}
/* in case several groups are specified in a single line
* split these groups in a single element for the list */
if (!token) {
ret = 0;
break;
}
if (!grouplist) {
SYSERROR("failed to allocate groups list");
break;
}
break;
}
}
return ret;
}
{
return 0;
}
{
}
{
return 0;
}
{
}
{
}
{
int ret;
// store these values in the lxc_conf, and then try to set for
// actual current logging.
if (ret == 0)
return ret;
}
{
int newlevel;
return 0;
if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET) {
DEBUG("Log level already set - ignoring new value");
return 0;
}
else
// store these values in the lxc_conf, and then try to set for
// actual current logging.
return lxc_log_set_level(newlevel);
}
{
return 0;
}
{
int n;
errno = 0;
return -1;
return n;
}
static int rt_sig_num(const char *signame)
{
int sig_n = 0;
int rtmax = 0;
rtmax = 1;
}
signame += 4;
return -1;
return -1;
return sig_n;
}
int n;
}
return "";
}
int n;
signame += 3;
}
}
return -1;
}
{
if (sig_n < 0)
return -1;
return 0;
}
{
if (sig_n < 0)
return -1;
return 0;
}
{
char *subkey;
if (!subkey)
return -1;
return -1;
return -1;
if (!cglist)
goto out;
if (!cgelem)
goto out;
goto out;
return 0;
out:
if (cglist)
if (cgelem) {
}
return -1;
}
{
char *token = "lxc.id_map";
char *subkey;
char type;
int ret;
return lxc_clear_idmaps(lxc_conf);
if (!subkey)
return -1;
return -1;
if (!idmaplist)
goto out;
if (!idmap)
goto out;
if (ret != 4)
goto out;
if (type == 'u')
else if (type == 'g')
else
goto out;
return 0;
out:
if (idmaplist)
if (idmap) {
}
return -1;
}
{
}
{
* no options: keep mask and flag identical and just define the
* enum value as an unused bit so far
*/
{ NULL, 0 }
};
int i;
int ret = -1;
return -1;
if (!autos) {
return -1;
}
if (!token) {
ret = 0;
break;
}
for (i = 0; allowed_auto_mounts[i].token; i++) {
break;
}
if (!allowed_auto_mounts[i].token) {
break;
}
}
return ret;
}
{
char *fstab_token = "lxc.mount";
char *token = "lxc.mount.entry";
char *auto_token = "lxc.mount.auto";
char *subkey;
char *mntelem;
return lxc_clear_mount_entries(lxc_conf);
if (!subkey) {
if (!subkey) {
if (!subkey)
return -1;
}
}
return -1;
if (!mntlist)
return -1;
if (!mntelem) {
return -1;
}
return 0;
}
{
int ret = -1;
return lxc_clear_config_keepcaps(lxc_conf);
if (!keepcaps) {
return -1;
}
/* in case several capability keep is specified in a single line
* split these caps in a single element for the list */
if (!token) {
ret = 0;
break;
}
if (!keeplist) {
SYSERROR("failed to allocate keepcap list");
break;
}
break;
}
}
return ret;
}
{
int ret = -1;
return lxc_clear_config_caps(lxc_conf);
if (!dropcaps) {
return -1;
}
/* in case several capability drop is specified in a single line
* split these caps in a single element for the list */
if (!token) {
ret = 0;
break;
}
if (!droplist) {
SYSERROR("failed to allocate drop list");
break;
}
break;
}
}
return ret;
}
{
}
{
}
{
}
{
}
{
}
{
if (!utsname) {
SYSERROR("failed to allocate memory");
return -1;
}
ERROR("node name '%s' is too long",
return -1;
}
return 0;
}
{
struct lxc_config_t *config;
char *dot;
char *key;
char *value;
int ret = 0;
if (lxc_is_line_empty(buffer))
return 0;
/* we have to dup the buffer otherwise, at the re-exec for
* reboot we modified the original string on the stack by
* replacing '=' by '\0' below
*/
if (!line) {
return -1;
}
/* martian option - ignoring it, the commented lines beginning by '#'
* fall in this case
*/
goto out;
ret = -1;
if (!dot) {
goto out;
}
*dot = '\0';
if (!config) {
goto out;
}
out:
return ret;
}
{
}
{
return -1;
}
/* Catch only the top level config file name in the structure */
}
}
{
if (!dent)
return -1;
return 0;
}
{
int ret = 0;
if (ret)
break;
}
}
return ret;
}
signed long lxc_config_parse_arch(const char *arch)
{
struct per_name {
char *name;
unsigned long per;
} pername[4] = {
{ "x86", PER_LINUX32 },
{ "i686", PER_LINUX32 },
{ "x86_64", PER_LINUX },
{ "amd64", PER_LINUX },
};
int i;
for (i = 0; i < len; i++) {
}
#endif
return -1;
}
{
int i, aflag;
{ "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
{ "CAP", LXC_ATTACH_DROP_CAPABILITIES },
{ "LSM", LXC_ATTACH_LSM_EXEC },
{ NULL, 0 }
};
if (!flaglist) {
/* for the sake of backward compatibility, drop all privileges
if none is specified */
}
return 0;
}
while (token) {
aflag = -1;
}
if (aflag < 0)
return -1;
}
return 0;
}
{
if (!retv)
inlen = 0;
else
}
{
int fulllen = 0;
if (!retv)
inlen = 0;
else
int len = 0;
switch(c->personality) {
default: break;
}
#endif
return fulllen;
}
/*
* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
* then just the value(s) will be printed. Since there still could be
* more than one, it is newline-separated.
* (Maybe that's ambigous, since some values, i.e. devices.list, will
* already have newlines?)
* If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
* in 'lxc.cgroup.subsystem.key = value' format.
*/
const char *key)
{
int all = 0;
if (!retv)
inlen = 0;
else
all = 1;
if (all) {
}
}
return fulllen;
}
const char *key)
{
char *subkey;
int i;
/* "lxc.hook.mount" */
if (!subkey)
return -1;
subkey++;
if (!*subkey)
return -1;
for (i=0; i<NUM_LXC_HOOKS; i++) {
found=i;
break;
}
}
if (found == -1)
return -1;
if (!retv)
inlen = 0;
else
}
return fulllen;
}
{
if (!retv)
inlen = 0;
else
}
return fulllen;
}
{
if (!retv)
inlen = 0;
else
}
return fulllen;
}
{
if (!retv)
inlen = 0;
else
}
return fulllen;
}
{
if (!retv)
inlen = 0;
else
}
return fulllen;
}
/*
* lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
* macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
* ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead
* of an address. ipv4 and ipv6 return lists (newline-separated).
* things like veth.pair return '' if invalid (i.e. if called for vlan
* type).
*/
const char *key)
{
char *p1;
struct lxc_netdev *netdev;
if (!retv)
inlen = 0;
else
p1++;
if (!netdev)
return -1;
if (netdev->downscript)
const char *mode;
default: mode = "(invalid)"; break;
}
}
}
}
if (netdev->ipv4_gateway_auto) {
} else if (netdev->ipv4_gateway) {
char buf[INET_ADDRSTRLEN];
}
char buf[INET_ADDRSTRLEN];
}
if (netdev->ipv6_gateway_auto) {
} else if (netdev->ipv6_gateway) {
char buf[INET_ADDRSTRLEN];
}
char buf[INET_ADDRSTRLEN];
}
}
return fulllen;
}
{
if (!retv)
inlen = 0;
else
const char *t = lxc_net_type_to_str(n->type);
}
return fulllen;
}
int inlen)
{
const char *v = NULL;
v = c->fstab;
v = c->ttydir;
v = c->lsm_aa_profile;
v = c->lsm_se_context;
v = lxc_log_get_file();
else return -1;
if (!v)
return 0;
return strlen(v);
}
{
return lxc_clear_config_network(c);
return lxc_clear_config_caps(c);
return lxc_clear_config_keepcaps(c);
return lxc_clear_cgroups(c, key);
return lxc_clear_mount_entries(c);
return lxc_clear_hooks(c, key);
return lxc_clear_groups(c);
return -1;
}
/*
* writing out a confile.
*/
{
int i;
if (c->fstab)
}
if (c->auto_mounts & LXC_AUTO_ALL_MASK) {
switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
default: break;
}
switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
default: break;
}
switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
default: break;
}
}
if (c->tty)
if (c->pts)
if (c->ttydir)
if (c->haltsignal)
if (c->stopsignal)
switch(c->personality) {
default: break;
}
#endif
if (c->lsm_aa_profile)
if (c->lsm_se_context)
if (c->seccomp)
if (c->kmsg == 0)
if (c->autodev)
if (c->loglevel != LXC_LOG_PRIORITY_NOTSET)
if (c->logfile)
}
if (c->utsname)
const char *t = lxc_net_type_to_str(n->type);
if (n->link)
if (n->name)
if (n->type == LXC_NET_MACVLAN) {
const char *mode;
default: mode = "(invalid)"; break;
}
} else if (n->type == LXC_NET_VETH) {
} else if (n->type == LXC_NET_VLAN) {
}
if (n->upscript)
if (n->downscript)
if (n->hwaddr)
if (n->mtu)
if (n->ipv4_gateway_auto)
else if (n->ipv4_gateway) {
char buf[INET_ADDRSTRLEN];
}
char buf[INET_ADDRSTRLEN];
}
if (n->ipv6_gateway_auto)
else if (n->ipv6_gateway) {
char buf[INET6_ADDRSTRLEN];
}
char buf[INET6_ADDRSTRLEN];
}
}
}
for (i=0; i<NUM_LXC_HOOKS; i++) {
}
if (c->start_auto)
if (c->start_delay)
if (c->start_order)
}