Unverified Commit 826a94a5 by Christian Brauner Committed by GitHub

Merge pull request #2544 from 2xsec/bugfix

tools: add default log priority & cleanups
parents 5493a1bf 34a10bfa
...@@ -45,6 +45,21 @@ ...@@ -45,6 +45,21 @@
lxc_log_define(lxc_attach, lxc); lxc_log_define(lxc_attach, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg);
static int add_to_simple_array(char ***array, ssize_t *capacity, char *value);
static bool stdfd_is_pty(void);
static int lxc_attach_create_log_file(const char *log_file);
static int elevated_privileges;
static signed long new_personality = -1;
static int namespace_flags = -1;
static int remount_sys_proc;
static lxc_attach_env_policy_t env_policy = LXC_ATTACH_KEEP_ENV;
static char **extra_env;
static ssize_t extra_env_size;
static char **extra_keep;
static ssize_t extra_keep_size;
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"elevated-privileges", optional_argument, 0, 'e'}, {"elevated-privileges", optional_argument, 0, 'e'},
{"arch", required_argument, 0, 'a'}, {"arch", required_argument, 0, 'a'},
...@@ -60,43 +75,60 @@ static const struct option my_longopts[] = { ...@@ -60,43 +75,60 @@ static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
static int elevated_privileges = 0; static struct lxc_arguments my_args = {
static signed long new_personality = -1; .progname = "lxc-attach",
static int namespace_flags = -1; .help = "\
static int remount_sys_proc = 0; --name=NAME [-- COMMAND]\n\
static lxc_attach_env_policy_t env_policy = LXC_ATTACH_KEEP_ENV; \n\
static char **extra_env = NULL; Execute the specified COMMAND - enter the container NAME\n\
static ssize_t extra_env_size = 0; \n\
static char **extra_keep = NULL; Options :\n\
static ssize_t extra_keep_size = 0; -n, --name=NAME NAME of the container\n\
-e, --elevated-privileges=PRIVILEGES\n\
static int add_to_simple_array(char ***array, ssize_t *capacity, char *value) Use elevated privileges instead of those of the\n\
{ container. If you don't specify privileges to be\n\
ssize_t count = 0; elevated as OR'd list: CAP, CGROUP and LSM (capabilities,\n\
cgroup and restrictions, respectively) then all of them\n\
if (!array) will be elevated.\n\
return -1; WARNING: This may leak privileges into the container.\n\
Use with care.\n\
if (*array) -a, --arch=ARCH Use ARCH for program instead of container's own\n\
for (; (*array)[count]; count++); architecture.\n\
-s, --namespaces=FLAGS\n\
/* we have to reallocate */ Don't attach to all the namespaces of the container\n\
if (count >= *capacity - 1) { but just to the following OR'd list of flags:\n\
ssize_t new_capacity = ((count + 1) / 32 + 1) * 32; MOUNT, PID, UTSNAME, IPC, USER or NETWORK.\n\
char **new_array = realloc((void*)*array, sizeof(char *) * new_capacity); WARNING: Using -s implies -e with all privileges\n\
if (!new_array) elevated, it may therefore leak privileges into the\n\
return -1; container. Use with care.\n\
memset(&new_array[count], 0, sizeof(char*)*(new_capacity - count)); -R, --remount-sys-proc\n\
*array = new_array; Remount /sys and /proc if not attaching to the\n\
*capacity = new_capacity; mount namespace when using -s in order to properly\n\
} reflect the correct namespace context. See the\n\
lxc-attach(1) manual page for details.\n\
if (!(*array)) --clear-env Clear all environment variables before attaching.\n\
return -1; The attached shell/program will start with only\n\
container=lxc set.\n\
(*array)[count] = value; --keep-env Keep all current environment variables. This\n\
return 0; is the current default behaviour, but is likely to\n\
} change in the future.\n\
-L, --pty-log=FILE\n\
Log pty output to FILE\n\
-v, --set-var Set an additional variable that is seen by the\n\
attached program in the container. May be specified\n\
multiple times.\n\
--keep-var Keep an additional environment variable. Only\n\
applicable if --clear-env is specified. May be used\n\
multiple times.\n\
-f, --rcfile=FILE\n\
Load configuration file FILE\n\
",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
};
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
...@@ -160,65 +192,45 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) ...@@ -160,65 +192,45 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
return 0; return 0;
} }
static struct lxc_arguments my_args = { static int add_to_simple_array(char ***array, ssize_t *capacity, char *value)
.progname = "lxc-attach", {
.help = "\ ssize_t count = 0;
--name=NAME [-- COMMAND]\n\
\n\ if (!array)
Execute the specified COMMAND - enter the container NAME\n\ return -1;
\n\
Options :\n\ if (*array)
-n, --name=NAME NAME of the container\n\ for (; (*array)[count]; count++);
-e, --elevated-privileges=PRIVILEGES\n\
Use elevated privileges instead of those of the\n\ /* we have to reallocate */
container. If you don't specify privileges to be\n\ if (count >= *capacity - 1) {
elevated as OR'd list: CAP, CGROUP and LSM (capabilities,\n\ ssize_t new_capacity = ((count + 1) / 32 + 1) * 32;
cgroup and restrictions, respectively) then all of them\n\
will be elevated.\n\ char **new_array = realloc((void*)*array, sizeof(char *) * new_capacity);
WARNING: This may leak privileges into the container.\n\ if (!new_array)
Use with care.\n\ return -1;
-a, --arch=ARCH Use ARCH for program instead of container's own\n\
architecture.\n\ memset(&new_array[count], 0, sizeof(char*)*(new_capacity - count));
-s, --namespaces=FLAGS\n\
Don't attach to all the namespaces of the container\n\ *array = new_array;
but just to the following OR'd list of flags:\n\ *capacity = new_capacity;
MOUNT, PID, UTSNAME, IPC, USER or NETWORK.\n\ }
WARNING: Using -s implies -e with all privileges\n\
elevated, it may therefore leak privileges into the\n\ if (!(*array))
container. Use with care.\n\ return -1;
-R, --remount-sys-proc\n\
Remount /sys and /proc if not attaching to the\n\ (*array)[count] = value;
mount namespace when using -s in order to properly\n\ return 0;
reflect the correct namespace context. See the\n\ }
lxc-attach(1) manual page for details.\n\
--clear-env Clear all environment variables before attaching.\n\
The attached shell/program will start with only\n\
container=lxc set.\n\
--keep-env Keep all current environment variables. This\n\
is the current default behaviour, but is likely to\n\
change in the future.\n\
-L, --pty-log=FILE\n\
Log pty output to FILE\n\
-v, --set-var Set an additional variable that is seen by the\n\
attached program in the container. May be specified\n\
multiple times.\n\
--keep-var Keep an additional environment variable. Only\n\
applicable if --clear-env is specified. May be used\n\
multiple times.\n\
-f, --rcfile=FILE\n\
Load configuration file FILE\n\
",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
};
static bool stdfd_is_pty(void) static bool stdfd_is_pty(void)
{ {
if (isatty(STDIN_FILENO)) if (isatty(STDIN_FILENO))
return true; return true;
if (isatty(STDOUT_FILENO)) if (isatty(STDOUT_FILENO))
return true; return true;
if (isatty(STDERR_FILENO)) if (isatty(STDERR_FILENO))
return true; return true;
...@@ -240,40 +252,34 @@ static int lxc_attach_create_log_file(const char *log_file) ...@@ -240,40 +252,34 @@ static int lxc_attach_create_log_file(const char *log_file)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret = -1, r; int ret = -1;
int wexit = 0; int wexit = 0;
struct lxc_log log; struct lxc_log log;
pid_t pid; pid_t pid;
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
r = lxc_caps_init(); if (lxc_caps_init())
if (r)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
r = lxc_arguments_parse(&my_args, argc, argv); if (lxc_arguments_parse(&my_args, argc, argv))
if (r)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
if (geteuid()) { if (geteuid())
if (access(my_args.lxcpath[0], O_RDONLY) < 0) { if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
ERROR("You lack access to %s", my_args.lxcpath[0]); ERROR("You lack access to %s", my_args.lxcpath[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
}
struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]); struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) if (!c)
......
...@@ -36,23 +36,15 @@ ...@@ -36,23 +36,15 @@
lxc_log_define(lxc_cgroup, lxc); lxc_log_define(lxc_cgroup, lxc);
static int my_checker(const struct lxc_arguments* args) static int my_checker(const struct lxc_arguments *args);
{
if (!args->argc) {
ERROR("Missing state object");
return -1;
}
return 0;
}
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-cgroup", .progname = "lxc-cgroup",
.help = "\ .help = "\
--name=NAME state-object [value]\n\ --name=NAME state-object [value]\n\
\n\ \n\
Get or set the value of a state object (for example, 'cpuset.cpus')\n\ Get or set the value of a state object (for example, 'cpuset.cpus')\n\
...@@ -61,11 +53,23 @@ in the container's cgroup for the corresponding subsystem.\n\ ...@@ -61,11 +53,23 @@ in the container's cgroup for the corresponding subsystem.\n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME of the container\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = my_checker, .checker = my_checker,
.log_priority = "ERROR",
.log_file = "none",
}; };
static int my_checker(const struct lxc_arguments *args)
{
if (!args->argc) {
ERROR("Missing state object");
return -1;
}
return 0;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *state_object = NULL, *value = NULL; char *state_object = NULL, *value = NULL;
...@@ -75,18 +79,15 @@ int main(int argc, char *argv[]) ...@@ -75,18 +79,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
state_object = my_args.argv[0]; state_object = my_args.argv[0];
...@@ -143,6 +144,7 @@ int main(int argc, char *argv[]) ...@@ -143,6 +144,7 @@ int main(int argc, char *argv[])
lxc_container_put(c); lxc_container_put(c);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
INFO("%*s", ret, buffer); INFO("%*s", ret, buffer);
} }
......
...@@ -30,16 +30,24 @@ ...@@ -30,16 +30,24 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
static char *checkpoint_dir = NULL; #define OPT_PREDUMP_DIR (OPT_USAGE + 1)
static bool stop = false;
static bool verbose = false;
static bool do_restore = false;
static bool daemonize_set = false;
static bool pre_dump = false;
static char *predump_dir = NULL;
static char *actionscript_path = NULL;
#define OPT_PREDUMP_DIR OPT_USAGE + 1 lxc_log_define(lxc_checkpoint, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg);
static int my_checker(const struct lxc_arguments *args);
static bool checkpoint(struct lxc_container *c);
static bool restore_finalize(struct lxc_container *c);
static bool restore(struct lxc_container *c);
static char *checkpoint_dir;
static bool stop;
static bool verbose;
static bool do_restore;
static bool daemonize_set;
static bool pre_dump;
static char *predump_dir;
static char *actionscript_path;
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"checkpoint-dir", required_argument, 0, 'D'}, {"checkpoint-dir", required_argument, 0, 'D'},
...@@ -54,31 +62,39 @@ static const struct option my_longopts[] = { ...@@ -54,31 +62,39 @@ static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
lxc_log_define(lxc_checkpoint, lxc); static struct lxc_arguments my_args = {
.progname = "lxc-checkpoint",
static int my_checker(const struct lxc_arguments *args) .help = "\
{ --name=NAME\n\
if (do_restore && stop) { \n\
ERROR("-s not compatible with -r"); lxc-checkpoint checkpoints and restores a container\n\
return -1; Serializes a container's running state to disk to allow restoring it in\n\
its running state at a later time.\n\
} else if (!do_restore && daemonize_set) { \n\
ERROR("-d/-F not compatible with -r"); Options :\n\
return -1; -n, --name=NAME NAME of the container\n\
} -r, --restore Restore container\n\
-D, --checkpoint-dir=DIR directory to save the checkpoint in\n\
if (!checkpoint_dir) { -v, --verbose Enable verbose criu logs\n\
ERROR("-D is required"); -A, --action-script=PATH Path to criu action script\n\
return -1; Checkpoint options:\n\
} -s, --stop Stop the container after checkpointing.\n\
-p, --pre-dump Only pre-dump the memory of the container.\n\
if (pre_dump && do_restore) { Container keeps on running and following\n\
ERROR("-p not compatible with -r"); checkpoints will only dump the changes.\n\
return -1; --predump-dir=DIR path to images from previous dump (relative to -D)\n\
} Restore options:\n\
-d, --daemon Daemonize the container (default)\n\
return 0; -F, --foreground Start with the current tty attached to /dev/console\n\
} --rcfile=FILE Load configuration file FILE\n\
",
.options = my_longopts,
.parser = my_parser,
.daemonize = 1,
.checker = my_checker,
.log_priority = "ERROR",
.log_file = "none",
};
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
...@@ -88,7 +104,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) ...@@ -88,7 +104,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
if (!checkpoint_dir) if (!checkpoint_dir)
return -1; return -1;
break; break;
case 'A': case 'A':
actionscript_path = strdup(arg); actionscript_path = strdup(arg);
if (!actionscript_path) if (!actionscript_path)
return -1; return -1;
...@@ -123,37 +139,29 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) ...@@ -123,37 +139,29 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
return 0; return 0;
} }
static struct lxc_arguments my_args = { static int my_checker(const struct lxc_arguments *args)
.progname = "lxc-checkpoint", {
.help = "\ if (do_restore && stop) {
--name=NAME\n\ ERROR("-s not compatible with -r");
\n\ return -1;
lxc-checkpoint checkpoints and restores a container\n\
Serializes a container's running state to disk to allow restoring it in\n\ } else if (!do_restore && daemonize_set) {
its running state at a later time.\n\ ERROR("-d/-F not compatible with -r");
\n\ return -1;
Options :\n\ }
-n, --name=NAME NAME of the container\n\
-r, --restore Restore container\n\ if (!checkpoint_dir) {
-D, --checkpoint-dir=DIR directory to save the checkpoint in\n\ ERROR("-D is required");
-v, --verbose Enable verbose criu logs\n\ return -1;
-A, --action-script=PATH Path to criu action script\n\ }
Checkpoint options:\n\
-s, --stop Stop the container after checkpointing.\n\ if (pre_dump && do_restore) {
-p, --pre-dump Only pre-dump the memory of the container.\n\ ERROR("-p not compatible with -r");
Container keeps on running and following\n\ return -1;
checkpoints will only dump the changes.\n\ }
--predump-dir=DIR path to images from previous dump (relative to -D)\n\
Restore options:\n\ return 0;
-d, --daemon Daemonize the container (default)\n\ }
-F, --foreground Start with the current tty attached to /dev/console\n\
--rcfile=FILE Load configuration file FILE\n\
",
.options = my_longopts,
.parser = my_parser,
.daemonize = 1,
.checker = my_checker,
};
static bool checkpoint(struct lxc_container *c) static bool checkpoint(struct lxc_container *c)
{ {
...@@ -262,18 +270,15 @@ int main(int argc, char *argv[]) ...@@ -262,18 +270,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
......
...@@ -44,28 +44,8 @@ ...@@ -44,28 +44,8 @@
lxc_log_define(lxc_console, lxc); lxc_log_define(lxc_console, lxc);
static char etoc(const char *expr) static int my_parser(struct lxc_arguments *args, int c, char *arg);
{ static char etoc(const char *expr);
/* returns "control code" of given expression */
char c = expr[0] == '^' ? expr[1] : expr[0];
return 1 + ((c > 'Z') ? (c - 'a') : (c - 'Z'));
}
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 't':
if (lxc_safe_uint(arg, &args->ttynum) < 0)
return -1;
break;
case 'e':
args->escape = etoc(arg);
break;
}
return 0;
}
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"tty", required_argument, 0, 't'}, {"tty", required_argument, 0, 't'},
...@@ -74,8 +54,8 @@ static const struct option my_longopts[] = { ...@@ -74,8 +54,8 @@ static const struct option my_longopts[] = {
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-console", .progname = "lxc-console",
.help = "\ .help = "\
--name=NAME [--tty NUMBER]\n\ --name=NAME [--tty NUMBER]\n\
\n\ \n\
lxc-console logs on the container with the identifier NAME\n\ lxc-console logs on the container with the identifier NAME\n\
...@@ -85,35 +65,56 @@ Options :\n\ ...@@ -85,35 +65,56 @@ Options :\n\
-t, --tty=NUMBER console tty number\n\ -t, --tty=NUMBER console tty number\n\
-e, --escape=PREFIX prefix for escape command\n\ -e, --escape=PREFIX prefix for escape command\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
.ttynum = -1, .log_priority = "ERROR",
.escape = 1, .log_file = "none",
.ttynum = -1,
.escape = 1,
}; };
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 't':
if (lxc_safe_uint(arg, &args->ttynum) < 0)
return -1;
break;
case 'e':
args->escape = etoc(arg);
break;
}
return 0;
}
static char etoc(const char *expr)
{
/* returns "control code" of given expression */
char c = expr[0] == '^' ? expr[1] : expr[0];
return 1 + ((c > 'Z') ? (c - 'a') : (c - 'Z'));
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret; int ret;
struct lxc_container *c; struct lxc_container *c;
struct lxc_log log; struct lxc_log log;
ret = lxc_arguments_parse(&my_args, argc, argv); if (lxc_arguments_parse(&my_args, argc, argv))
if (ret)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
......
...@@ -31,64 +31,15 @@ ...@@ -31,64 +31,15 @@
#include "arguments.h" #include "arguments.h"
#include "log.h" #include "log.h"
#include "storage_utils.h"
#include "utils.h" #include "utils.h"
lxc_log_define(lxc_create, lxc); lxc_log_define(lxc_create, lxc);
static uint64_t get_fssize(char *s) static int my_parser(struct lxc_arguments *args, int c, char *arg);
{ static uint64_t get_fssize(char *s);
uint64_t ret; static void create_helpfn(const struct lxc_arguments *args);
char *end; static bool validate_bdev_args(struct lxc_arguments *args);
ret = strtoull(s, &end, 0);
if (end == s)
{
ERROR("Invalid blockdev size '%s', using default size", s);
return 0;
}
while (isblank(*end))
end++;
if (*end == '\0')
ret *= 1024ULL * 1024ULL; /* MB by default */
else if (*end == 'b' || *end == 'B')
ret *= 1ULL;
else if (*end == 'k' || *end == 'K')
ret *= 1024ULL;
else if (*end == 'm' || *end == 'M')
ret *= 1024ULL * 1024ULL;
else if (*end == 'g' || *end == 'G')
ret *= 1024ULL * 1024ULL * 1024ULL;
else if (*end == 't' || *end == 'T')
ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
else
{
ERROR("Invalid blockdev unit size '%c' in '%s', using default size", *end, s);
return 0;
}
return ret;
}
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 'B': args->bdevtype = arg; break;
case 'f': args->configfile = arg; break;
case 't': args->template = arg; break;
case '0': args->lvname = arg; break;
case '1': args->vgname = arg; break;
case '2': args->thinpool = arg; break;
case '3': args->fstype = arg; break;
case '4': args->fssize = get_fssize(arg); break;
case '5': args->zfsroot = arg; break;
case '6': args->dir = arg; break;
case '7': args->rbdname = arg; break;
case '8': args->rbdpool = arg; break;
}
return 0;
}
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"bdev", required_argument, 0, 'B'}, {"bdev", required_argument, 0, 'B'},
...@@ -106,35 +57,10 @@ static const struct option my_longopts[] = { ...@@ -106,35 +57,10 @@ static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
static void create_helpfn(const struct lxc_arguments *args)
{
char *argv[3], *path;
pid_t pid;
if (!args->template)
return;
pid = fork();
if (pid) {
(void)wait_for_pid(pid);
return;
}
path = get_template_path(args->template);
argv[0] = path;
argv[1] = "-h";
argv[2] = NULL;
execv(path, argv);
ERROR("Error executing %s -h", path);
_exit(EXIT_FAILURE);
}
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-create", .progname = "lxc-create",
.helpfn = create_helpfn, .helpfn = create_helpfn,
.help = "\ .help = "\
--name=NAME --template=TEMPLATE [OPTION...]\n\ --name=NAME --template=TEMPLATE [OPTION...]\n\
\n\ \n\
lxc-create creates a container\n\ lxc-create creates a container\n\
...@@ -170,64 +96,148 @@ Options :\n\ ...@@ -170,64 +96,148 @@ Options :\n\
--fssize=SIZE[U] Create filesystem of\n\ --fssize=SIZE[U] Create filesystem of\n\
size SIZE * unit U (bBkKmMgGtT)\n\ size SIZE * unit U (bBkKmMgGtT)\n\
(Default: 1G, default unit: M)\n", (Default: 1G, default unit: M)\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
}; };
static bool validate_bdev_args(struct lxc_arguments *a) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 'B':
args->bdevtype = arg;
break;
case 'f':
args->configfile = arg;
break;
case 't':
args->template = arg;
break;
case '0':
args->lvname = arg;
break;
case '1':
args->vgname = arg;
break;
case '2':
args->thinpool = arg;
break;
case '3':
args->fstype = arg;
break;
case '4':
args->fssize = get_fssize(arg);
break;
case '5':
args->zfsroot = arg;
break;
case '6':
args->dir = arg;
break;
case '7':
args->rbdname = arg;
break;
case '8':
args->rbdpool = arg;
break;
}
return 0;
}
static uint64_t get_fssize(char *s)
{
uint64_t ret;
char *end;
ret = strtoull(s, &end, 0);
if (end == s) {
ERROR("Invalid blockdev size '%s', using default size", s);
return 0;
}
while (isblank(*end))
end++;
if (*end == '\0') {
ret *= 1024ULL * 1024ULL; /* MB by default */
} else if (*end == 'b' || *end == 'B') {
ret *= 1ULL;
} else if (*end == 'k' || *end == 'K') {
ret *= 1024ULL;
} else if (*end == 'm' || *end == 'M') {
ret *= 1024ULL * 1024ULL;
} else if (*end == 'g' || *end == 'G') {
ret *= 1024ULL * 1024ULL * 1024ULL;
} else if (*end == 't' || *end == 'T') {
ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
} else {
ERROR("Invalid blockdev unit size '%c' in '%s', using default size", *end, s);
return 0;
}
return ret;
}
static void create_helpfn(const struct lxc_arguments *args)
{
char *argv[3], *path;
pid_t pid;
if (!args->template)
return;
pid = fork();
if (pid) {
(void)wait_for_pid(pid);
return;
}
path = get_template_path(args->template);
argv[0] = path;
argv[1] = "-h";
argv[2] = NULL;
execv(path, argv);
ERROR("Error executing %s -h", path);
_exit(EXIT_FAILURE);
}
static bool validate_bdev_args(struct lxc_arguments *args)
{ {
if (strncmp(a->bdevtype, "best", strlen(a->bdevtype)) != 0) { if (strncmp(args->bdevtype, "best", strlen(args->bdevtype)) != 0) {
if (a->fstype || a->fssize) { if (args->fstype || args->fssize)
if (strncmp(a->bdevtype, "lvm", strlen(a->bdevtype)) != 0 && if (strncmp(args->bdevtype, "lvm", strlen(args->bdevtype)) != 0 &&
strncmp(a->bdevtype, "loop", strlen(a->bdevtype)) != 0 && strncmp(args->bdevtype, "loop", strlen(args->bdevtype)) != 0 &&
strncmp(a->bdevtype, "rbd", strlen(a->bdevtype)) != 0) { strncmp(args->bdevtype, "rbd", strlen(args->bdevtype)) != 0) {
ERROR("Filesystem type and size are only valid with block devices"); ERROR("Filesystem type and size are only valid with block devices");
return false; return false;
} }
}
if (strncmp(a->bdevtype, "lvm", strlen(a->bdevtype)) != 0) { if (strncmp(args->bdevtype, "lvm", strlen(args->bdevtype)) != 0)
if (a->lvname || a->vgname || a->thinpool) { if (args->lvname || args->vgname || args->thinpool) {
ERROR("--lvname, --vgname and --thinpool are only valid with -B lvm"); ERROR("--lvname, --vgname and --thinpool are only valid with -B lvm");
return false; return false;
} }
}
if (strncmp(a->bdevtype, "rbd", strlen(a->bdevtype)) != 0) { if (strncmp(args->bdevtype, "rbd", strlen(args->bdevtype)) != 0)
if (a->rbdname || a->rbdpool) { if (args->rbdname || args->rbdpool) {
ERROR("--rbdname and --rbdpool are only valid with -B rbd"); ERROR("--rbdname and --rbdpool are only valid with -B rbd");
return false; return false;
} }
}
if (strncmp(a->bdevtype, "zfs", strlen(a->bdevtype)) != 0) { if (strncmp(args->bdevtype, "zfs", strlen(args->bdevtype)) != 0)
if (a->zfsroot) { if (args->zfsroot) {
ERROR("zfsroot is only valid with -B zfs"); ERROR("zfsroot is only valid with -B zfs");
return false; return false;
} }
}
} }
return true; return true;
} }
static bool is_valid_storage_type(const char *type)
{
if (strcmp(type, "dir") == 0 ||
strcmp(type, "btrfs") == 0 ||
strcmp(type, "loop") == 0 ||
strcmp(type, "lvm") == 0 ||
strcmp(type, "nbd") == 0 ||
strcmp(type, "overlay") == 0 ||
strcmp(type, "overlayfs") == 0 ||
strcmp(type, "rbd") == 0 ||
strcmp(type, "zfs") == 0)
return true;
return false;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct lxc_container *c; struct lxc_container *c;
...@@ -238,21 +248,15 @@ int main(int argc, char *argv[]) ...@@ -238,21 +248,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
if (!my_args.log_file) log.prefix = my_args.progname;
log.file = "none"; log.quiet = my_args.quiet;
else log.lxcpath = my_args.lxcpath[0];
log.file = my_args.log_file;
log.level = my_args.log_priority; if (lxc_log_init(&log))
log.prefix = my_args.progname; exit(EXIT_FAILURE);
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log))
exit(EXIT_FAILURE);
}
if (!my_args.template) { if (!my_args.template) {
ERROR("A template must be specified"); ERROR("A template must be specified");
...@@ -318,13 +322,12 @@ int main(int argc, char *argv[]) ...@@ -318,13 +322,12 @@ int main(int argc, char *argv[])
spec.fssize = my_args.fssize; spec.fssize = my_args.fssize;
if ((strncmp(my_args.bdevtype, "zfs", strlen(my_args.bdevtype)) == 0) || if ((strncmp(my_args.bdevtype, "zfs", strlen(my_args.bdevtype)) == 0) ||
(strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0)) { (strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0))
if (my_args.zfsroot) if (my_args.zfsroot)
spec.zfs.zfsroot = my_args.zfsroot; spec.zfs.zfsroot = my_args.zfsroot;
}
if ((strncmp(my_args.bdevtype, "lvm", strlen(my_args.bdevtype)) == 0) || if ((strncmp(my_args.bdevtype, "lvm", strlen(my_args.bdevtype)) == 0) ||
(strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0)) { (strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0)) {
if (my_args.lvname) if (my_args.lvname)
spec.lvm.lv = my_args.lvname; spec.lvm.lv = my_args.lvname;
...@@ -336,7 +339,7 @@ int main(int argc, char *argv[]) ...@@ -336,7 +339,7 @@ int main(int argc, char *argv[])
} }
if ((strncmp(my_args.bdevtype, "rbd", strlen(my_args.bdevtype)) == 0) || if ((strncmp(my_args.bdevtype, "rbd", strlen(my_args.bdevtype)) == 0) ||
(strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0)) { (strncmp(my_args.bdevtype, "best", strlen(my_args.bdevtype)) == 0)) {
if (my_args.rbdname) if (my_args.rbdname)
spec.rbd.rbdname = my_args.rbdname; spec.rbd.rbdname = my_args.rbdname;
...@@ -354,7 +357,7 @@ int main(int argc, char *argv[]) ...@@ -354,7 +357,7 @@ int main(int argc, char *argv[])
flags = LXC_CREATE_QUIET; flags = LXC_CREATE_QUIET;
if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) { if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
fprintf(stderr, "Error creating container %s\n", c->name); ERROR("Failed to create container %s", c->name);
lxc_container_put(c); lxc_container_put(c);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
lxc_log_define(lxc_destroy, lxc); lxc_log_define(lxc_destroy, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg); static int my_parser(struct lxc_arguments *args, int c, char *arg);
static bool do_destroy(struct lxc_container *c);
static bool do_destroy_with_snapshots(struct lxc_container *c);
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"force", no_argument, 0, 'f'}, {"force", no_argument, 0, 'f'},
...@@ -43,8 +45,8 @@ static const struct option my_longopts[] = { ...@@ -43,8 +45,8 @@ static const struct option my_longopts[] = {
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-destroy", .progname = "lxc-destroy",
.help = "\ .help = "\
--name=NAME [-f] [-P lxcpath]\n\ --name=NAME [-f] [-P lxcpath]\n\
\n\ \n\
lxc-destroy destroys a container with the identifier NAME\n\ lxc-destroy destroys a container with the identifier NAME\n\
...@@ -54,106 +56,35 @@ Options :\n\ ...@@ -54,106 +56,35 @@ Options :\n\
-s, --snapshots destroy including all snapshots\n\ -s, --snapshots destroy including all snapshots\n\
-f, --force wait for the container to shut down\n\ -f, --force wait for the container to shut down\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
.task = DESTROY, .log_priority = "ERROR",
.log_file = "none",
.task = DESTROY,
}; };
static bool do_destroy(struct lxc_container *c);
static bool do_destroy_with_snapshots(struct lxc_container *c);
int main(int argc, char *argv[])
{
struct lxc_container *c;
struct lxc_log log;
bool bret;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */
if (my_args.log_file || my_args.log_priority) {
log.name = my_args.name;
log.file = my_args.log_file;
log.level = my_args.log_priority;
log.prefix = my_args.progname;
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log))
exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
ERROR("System error loading container");
exit(EXIT_FAILURE);
}
if (my_args.rcfile) {
c->clear_config(c);
if (!c->load_config(c, my_args.rcfile)) {
ERROR("Failed to load rcfile");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
c->configfile = strdup(my_args.rcfile);
if (!c->configfile) {
ERROR("Out of memory setting new config filename");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
}
if (!c->may_control(c)) {
ERROR("Insufficent privileges to control %s", my_args.name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (!c->is_defined(c)) {
ERROR("Container is not defined");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (my_args.task == SNAP) {
bret = do_destroy_with_snapshots(c);
if (bret)
ERROR("Destroyed container %s including snapshots", my_args.name);
} else {
bret = do_destroy(c);
if (bret)
ERROR("Destroyed container %s", my_args.name);
}
lxc_container_put(c);
if (bret)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
switch (c) { switch (c) {
case 'f': args->force = 1; break; case 'f':
case 's': args->task = SNAP; break; args->force = 1;
break;
case 's':
args->task = SNAP;
break;
} }
return 0; return 0;
} }
static bool do_destroy(struct lxc_container *c) static bool do_destroy(struct lxc_container *c)
{ {
int ret;
bool bret = true; bool bret = true;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
/* First check whether the container has dependent clones or snapshots. */ /* First check whether the container has dependent clones or snapshots. */
int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name); ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return false; return false;
...@@ -187,9 +118,8 @@ static bool do_destroy(struct lxc_container *c) ...@@ -187,9 +118,8 @@ static bool do_destroy(struct lxc_container *c)
char buf[256]; char buf[256];
ret = c->get_config_item(c, "lxc.ephemeral", buf, 256); ret = c->get_config_item(c, "lxc.ephemeral", buf, 256);
if (ret > 0 && strcmp(buf, "0") == 0) { if (ret > 0 && strcmp(buf, "0") == 0)
bret = c->destroy(c); bret = c->destroy(c);
}
} }
if (!bret) { if (!bret) {
...@@ -273,3 +203,75 @@ static bool do_destroy_with_snapshots(struct lxc_container *c) ...@@ -273,3 +203,75 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
return bret; return bret;
} }
int main(int argc, char *argv[])
{
struct lxc_container *c;
struct lxc_log log;
bool bret;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE);
log.name = my_args.name;
log.file = my_args.log_file;
log.level = my_args.log_priority;
log.prefix = my_args.progname;
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log))
exit(EXIT_FAILURE);
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
ERROR("System error loading container");
exit(EXIT_FAILURE);
}
if (my_args.rcfile) {
c->clear_config(c);
if (!c->load_config(c, my_args.rcfile)) {
ERROR("Failed to load rcfile");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
c->configfile = strdup(my_args.rcfile);
if (!c->configfile) {
ERROR("Out of memory setting new config filename");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
}
if (!c->may_control(c)) {
ERROR("Insufficent privileges to control %s", my_args.name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (!c->is_defined(c)) {
ERROR("Container is not defined");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (my_args.task == SNAP) {
bret = do_destroy_with_snapshots(c);
if (bret)
ERROR("Destroyed container %s including snapshots", my_args.name);
} else {
bret = do_destroy(c);
if (bret)
ERROR("Destroyed container %s", my_args.name);
}
lxc_container_put(c);
if (bret)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
...@@ -33,21 +33,23 @@ ...@@ -33,21 +33,23 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
lxc_log_define(lxc_device, lxc);
#if HAVE_IFADDRS_H #if HAVE_IFADDRS_H
#include <ifaddrs.h> #include <ifaddrs.h>
#else #else
#include "include/ifaddrs.h" #include "include/ifaddrs.h"
#endif #endif
lxc_log_define(lxc_device, lxc);
static bool is_interface(const char *dev_name, pid_t pid);
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-device", .progname = "lxc-device",
.help = "\ .help = "\
--name=NAME -- add|del DEV\n\ --name=NAME -- add|del DEV\n\
\n\ \n\
lxc-device attach or detach DEV to or from container.\n\ lxc-device attach or detach DEV to or from container.\n\
...@@ -55,9 +57,11 @@ lxc-device attach or detach DEV to or from container.\n\ ...@@ -55,9 +57,11 @@ lxc-device attach or detach DEV to or from container.\n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME of the container\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
}; };
static bool is_interface(const char *dev_name, pid_t pid) static bool is_interface(const char *dev_name, pid_t pid)
...@@ -110,25 +114,22 @@ int main(int argc, char *argv[]) ...@@ -110,25 +114,22 @@ int main(int argc, char *argv[])
} }
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
goto err; exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0]; if (lxc_log_init(&log))
exit(EXIT_FAILURE);
if (lxc_log_init(&log))
exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
ERROR("%s doesn't exist", my_args.name); ERROR("%s doesn't exist", my_args.name);
goto err; exit(EXIT_FAILURE);
} }
if (my_args.rcfile) { if (my_args.rcfile) {
...@@ -136,65 +137,60 @@ int main(int argc, char *argv[]) ...@@ -136,65 +137,60 @@ int main(int argc, char *argv[])
if (!c->load_config(c, my_args.rcfile)) { if (!c->load_config(c, my_args.rcfile)) {
ERROR("Failed to load rcfile"); ERROR("Failed to load rcfile");
goto err1; goto err;
} }
c->configfile = strdup(my_args.rcfile); c->configfile = strdup(my_args.rcfile);
if (!c->configfile) { if (!c->configfile) {
ERROR("Out of memory setting new config filename"); ERROR("Out of memory setting new config filename");
goto err1; goto err;
} }
} }
if (!c->is_running(c)) { if (!c->is_running(c)) {
ERROR("Container %s is not running", c->name); ERROR("Container %s is not running", c->name);
goto err1; goto err;
} }
if (my_args.argc < 2) { if (my_args.argc < 2) {
ERROR("Error: no command given (Please see --help output)"); ERROR("Error: no command given (Please see --help output)");
goto err1; goto err;
} }
cmd = my_args.argv[0]; cmd = my_args.argv[0];
dev_name = my_args.argv[1]; dev_name = my_args.argv[1];
if (my_args.argc < 3) if (my_args.argc < 3)
dst_name = dev_name; dst_name = dev_name;
else else
dst_name = my_args.argv[2]; dst_name = my_args.argv[2];
if (strncmp(cmd, "add", strlen(cmd)) == 0) { if (strncmp(cmd, "add", strlen(cmd)) == 0) {
if (is_interface(dev_name, 1)) { if (is_interface(dev_name, 1))
ret = c->attach_interface(c, dev_name, dst_name); ret = c->attach_interface(c, dev_name, dst_name);
} else { else
ret = c->add_device_node(c, dev_name, dst_name); ret = c->add_device_node(c, dev_name, dst_name);
}
if (ret != true) { if (ret != true) {
ERROR("Failed to add %s to %s", dev_name, c->name); ERROR("Failed to add %s to %s", dev_name, c->name);
goto err1; goto err;
} }
} else if (strncmp(cmd, "del", strlen(cmd)) == 0) { } else if (strncmp(cmd, "del", strlen(cmd)) == 0) {
if (is_interface(dev_name, c->init_pid(c))) { if (is_interface(dev_name, c->init_pid(c)))
ret = c->detach_interface(c, dev_name, dst_name); ret = c->detach_interface(c, dev_name, dst_name);
} else { else
ret = c->remove_device_node(c, dev_name, dst_name); ret = c->remove_device_node(c, dev_name, dst_name);
}
if (ret != true) { if (ret != true) {
ERROR("Failed to del %s from %s", dev_name, c->name); ERROR("Failed to del %s from %s", dev_name, c->name);
goto err1; goto err;
} }
} else { } else {
ERROR("Error: Please use add or del (Please see --help output)"); ERROR("Error: Please use add or del (Please see --help output)");
goto err1; goto err;
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
err1:
lxc_container_put(c);
err: err:
lxc_container_put(c);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -43,8 +43,46 @@ ...@@ -43,8 +43,46 @@
lxc_log_define(lxc_execute, lxc); lxc_log_define(lxc_execute, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg);
static bool set_argv(struct lxc_container *c, struct lxc_arguments *args);
static struct lxc_list defines; static struct lxc_list defines;
static const struct option my_longopts[] = {
{"daemon", no_argument, 0, 'd'},
{"rcfile", required_argument, 0, 'f'},
{"define", required_argument, 0, 's'},
{"uid", required_argument, 0, 'u'},
{"gid", required_argument, 0, 'g'},
{"share-net", required_argument, 0, OPT_SHARE_NET},
{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
{"share-uts", required_argument, 0, OPT_SHARE_UTS},
{"share-pid", required_argument, 0, OPT_SHARE_PID},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-execute",
.help = "\
--name=NAME -- COMMAND\n\
\n\
lxc-execute creates a container with the identifier NAME\n\
and execs COMMAND into this container.\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-d, --daemon Daemonize the container\n\
-f, --rcfile=FILE Load configuration file FILE\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
-u, --uid=UID Execute COMMAND with UID inside the container\n\
-g, --gid=GID Execute COMMAND with GID inside the container\n",
.options = my_longopts,
.parser = my_parser,
.log_priority = "ERROR",
.log_file = "none",
.daemonize = 0,
};
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
int ret; int ret;
...@@ -82,43 +120,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) ...@@ -82,43 +120,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
args->share_ns[LXC_NS_PID] = arg; args->share_ns[LXC_NS_PID] = arg;
break; break;
} }
return 0; return 0;
} }
static const struct option my_longopts[] = {
{"daemon", no_argument, 0, 'd'},
{"rcfile", required_argument, 0, 'f'},
{"define", required_argument, 0, 's'},
{"uid", required_argument, 0, 'u'},
{"gid", required_argument, 0, 'g'},
{"share-net", required_argument, 0, OPT_SHARE_NET},
{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
{"share-uts", required_argument, 0, OPT_SHARE_UTS},
{"share-pid", required_argument, 0, OPT_SHARE_PID},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-execute",
.help = "\
--name=NAME -- COMMAND\n\
\n\
lxc-execute creates a container with the identifier NAME\n\
and execs COMMAND into this container.\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-d, --daemon Daemonize the container\n\
-f, --rcfile=FILE Load configuration file FILE\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
-u, --uid=UID Execute COMMAND with UID inside the container\n\
-g, --gid=GID Execute COMMAND with GID inside the container\n",
.options = my_longopts,
.parser = my_parser,
.daemonize = 0,
};
static bool set_argv(struct lxc_container *c, struct lxc_arguments *args) static bool set_argv(struct lxc_container *c, struct lxc_arguments *args)
{ {
int ret; int ret;
...@@ -134,6 +138,7 @@ static bool set_argv(struct lxc_container *c, struct lxc_arguments *args) ...@@ -134,6 +138,7 @@ static bool set_argv(struct lxc_container *c, struct lxc_arguments *args)
return false; return false;
args->argv = components; args->argv = components;
for (p = components; *p; p++) for (p = components; *p; p++)
args->argc++; args->argc++;
...@@ -156,18 +161,15 @@ int main(int argc, char *argv[]) ...@@ -156,18 +161,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(err); exit(err);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0]; if (lxc_log_init(&log))
exit(err);
if (lxc_log_init(&log))
exit(err);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
...@@ -195,12 +197,11 @@ int main(int argc, char *argv[]) ...@@ -195,12 +197,11 @@ int main(int argc, char *argv[])
goto out; goto out;
} }
if (my_args.argc == 0) { if (my_args.argc == 0)
if (!set_argv(c, &my_args)) { if (!set_argv(c, &my_args)) {
ERROR("Missing command to execute!"); ERROR("Missing command to execute!");
goto out; goto out;
} }
}
bret = lxc_config_define_load(&defines, c); bret = lxc_config_define_load(&defines, c);
if (!bret) if (!bret)
...@@ -244,12 +245,11 @@ int main(int argc, char *argv[]) ...@@ -244,12 +245,11 @@ int main(int argc, char *argv[])
if (c->daemonize) { if (c->daemonize) {
err = EXIT_SUCCESS; err = EXIT_SUCCESS;
} else { } else {
if (WIFEXITED(c->error_num)) { if (WIFEXITED(c->error_num))
err = WEXITSTATUS(c->error_num); err = WEXITSTATUS(c->error_num);
} else { else
/* Try to die with the same signal the task did. */ /* Try to die with the same signal the task did. */
kill(0, WTERMSIG(c->error_num)); kill(0, WTERMSIG(c->error_num));
}
} }
out: out:
......
...@@ -41,8 +41,8 @@ static const struct option my_longopts[] = { ...@@ -41,8 +41,8 @@ static const struct option my_longopts[] = {
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-freeze", .progname = "lxc-freeze",
.help = "\ .help = "\
--name=NAME\n\ --name=NAME\n\
\n\ \n\
lxc-freeze freezes a container with the identifier NAME\n\ lxc-freeze freezes a container with the identifier NAME\n\
...@@ -50,9 +50,11 @@ lxc-freeze freezes a container with the identifier NAME\n\ ...@@ -50,9 +50,11 @@ lxc-freeze freezes a container with the identifier NAME\n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME of the container\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
}; };
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -63,18 +65,15 @@ int main(int argc, char *argv[]) ...@@ -63,18 +65,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
......
...@@ -46,41 +46,58 @@ ...@@ -46,41 +46,58 @@
#include "confile.h" #include "confile.h"
#include "log.h" #include "log.h"
static struct lxc_list defines;
lxc_log_define(lxc_start, lxc); lxc_log_define(lxc_start, lxc);
static int ensure_path(struct lxc_arguments *args, char **confpath, const char *path) static int my_parser(struct lxc_arguments *args, int c, char *arg);
{ static int ensure_path(struct lxc_arguments *args, char **confpath, const char *path);
int err = -1, fd;
char *fullpath = NULL;
if (path) {
if (access(path, W_OK)) {
fd = creat(path, 0600);
if (fd < 0 && errno != EEXIST) {
ERROR("Failed to create '%s'", path);
goto err;
}
if (fd >= 0)
close(fd);
}
fullpath = realpath(path, NULL); static struct lxc_list defines;
if (!fullpath) {
ERROR("Failed to get the real path of '%s'", path);
goto err;
}
*confpath = fullpath;
}
err = EXIT_SUCCESS; static const struct option my_longopts[] = {
{"daemon", no_argument, 0, 'd'},
{"foreground", no_argument, 0, 'F'},
{"rcfile", required_argument, 0, 'f'},
{"define", required_argument, 0, 's'},
{"console", required_argument, 0, 'c'},
{"console-log", required_argument, 0, 'L'},
{"close-all-fds", no_argument, 0, 'C'},
{"pidfile", required_argument, 0, 'p'},
{"share-net", required_argument, 0, OPT_SHARE_NET},
{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
{"share-uts", required_argument, 0, OPT_SHARE_UTS},
{"share-pid", required_argument, 0, OPT_SHARE_PID},
LXC_COMMON_OPTIONS
};
err: static struct lxc_arguments my_args = {
return err; .progname = "lxc-start",
} .help = "\
--name=NAME -- COMMAND\n\
\n\
lxc-start start COMMAND in specified container NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-d, --daemon Daemonize the container (default)\n\
-F, --foreground Start with the current tty attached to /dev/console\n\
-p, --pidfile=FILE Create a file with the process id\n\
-f, --rcfile=FILE Load configuration file FILE\n\
-c, --console=FILE Use specified FILE for the container console\n\
-L, --console-log=FILE Log container console output to FILE\n\
-C, --close-all-fds If any fds are inherited, close them\n\
If not specified, exit with failure instead\n\
Note: --daemon implies --close-all-fds\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
--share-[net|ipc|uts|pid]=NAME Share a namespace with another container or pid\n\
",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
.daemonize = 1,
.pidfile = NULL,
};
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
...@@ -124,49 +141,34 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) ...@@ -124,49 +141,34 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
return 0; return 0;
} }
static const struct option my_longopts[] = { static int ensure_path(struct lxc_arguments *args, char **confpath, const char *path)
{"daemon", no_argument, 0, 'd'}, {
{"foreground", no_argument, 0, 'F'}, int fd;
{"rcfile", required_argument, 0, 'f'}, char *fullpath = NULL;
{"define", required_argument, 0, 's'},
{"console", required_argument, 0, 'c'},
{"console-log", required_argument, 0, 'L'},
{"close-all-fds", no_argument, 0, 'C'},
{"pidfile", required_argument, 0, 'p'},
{"share-net", required_argument, 0, OPT_SHARE_NET},
{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
{"share-uts", required_argument, 0, OPT_SHARE_UTS},
{"share-pid", required_argument, 0, OPT_SHARE_PID},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = { if (path) {
.progname = "lxc-start", if (access(path, W_OK)) {
.help = "\ fd = creat(path, 0600);
--name=NAME -- COMMAND\n\ if (fd < 0 && errno != EEXIST) {
\n\ ERROR("Failed to create '%s'", path);
lxc-start start COMMAND in specified container NAME\n\ return -1;
\n\ }
Options :\n\
-n, --name=NAME NAME of the container\n\ if (fd >= 0)
-d, --daemon Daemonize the container (default)\n\ close(fd);
-F, --foreground Start with the current tty attached to /dev/console\n\ }
-p, --pidfile=FILE Create a file with the process id\n\
-f, --rcfile=FILE Load configuration file FILE\n\ fullpath = realpath(path, NULL);
-c, --console=FILE Use specified FILE for the container console\n\ if (!fullpath) {
-L, --console-log=FILE Log container console output to FILE\n\ ERROR("Failed to get the real path of '%s'", path);
-C, --close-all-fds If any fds are inherited, close them\n\ return -1;
If not specified, exit with failure instead\n\ }
Note: --daemon implies --close-all-fds\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ *confpath = fullpath;
--share-[net|ipc|uts|pid]=NAME Share a namespace with another container or pid\n\ }
",
.options = my_longopts, return 0;
.parser = my_parser, }
.checker = NULL,
.daemonize = 1,
.pidfile = NULL,
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
...@@ -194,18 +196,15 @@ int main(int argc, char *argv[]) ...@@ -194,18 +196,15 @@ int main(int argc, char *argv[])
else else
args = my_args.argv; args = my_args.argv;
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(err); exit(err);
}
lxcpath = my_args.lxcpath[0]; lxcpath = my_args.lxcpath[0];
if (access(lxcpath, O_RDONLY) < 0) { if (access(lxcpath, O_RDONLY) < 0) {
...@@ -297,12 +296,11 @@ int main(int argc, char *argv[]) ...@@ -297,12 +296,11 @@ int main(int argc, char *argv[])
goto out; goto out;
} }
if (my_args.pidfile != NULL) { if (my_args.pidfile)
if (ensure_path(&my_args, &c->pidfile, my_args.pidfile) < 0) { if (ensure_path(&my_args, &c->pidfile, my_args.pidfile) < 0) {
ERROR("Failed to ensure pidfile '%s'", my_args.pidfile); ERROR("Failed to ensure pidfile '%s'", my_args.pidfile);
goto out; goto out;
} }
}
if (my_args.console) if (my_args.console)
if (!c->set_config_item(c, "lxc.console.path", my_args.console)) if (!c->set_config_item(c, "lxc.console.path", my_args.console))
...@@ -315,9 +313,8 @@ int main(int argc, char *argv[]) ...@@ -315,9 +313,8 @@ int main(int argc, char *argv[])
if (!lxc_setup_shared_ns(&my_args, c)) if (!lxc_setup_shared_ns(&my_args, c))
goto out; goto out;
if (!my_args.daemonize) { if (!my_args.daemonize)
c->want_daemonize(c, false); c->want_daemonize(c, false);
}
if (my_args.close_all_fds) if (my_args.close_all_fds)
c->want_close_all_fds(c, true); c->want_close_all_fds(c, true);
......
...@@ -34,36 +34,12 @@ ...@@ -34,36 +34,12 @@
#include "log.h" #include "log.h"
#include "utils.h" #include "utils.h"
#define OPT_NO_LOCK OPT_USAGE + 1 #define OPT_NO_LOCK (OPT_USAGE + 1)
#define OPT_NO_KILL OPT_USAGE + 2 #define OPT_NO_KILL (OPT_USAGE + 2)
lxc_log_define(lxc_stop, lxc); lxc_log_define(lxc_stop, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg);
{
switch (c) {
case 'r':
args->reboot = 1;
break;
case 'W':
args->nowait = 1;
break;
case 't':
if (lxc_safe_long(arg, &args->timeout) < 0)
return -1;
break;
case 'k':
args->hardstop = 1;
break;
case OPT_NO_LOCK:
args->nolock = 1;
break;
case OPT_NO_KILL:
args->nokill = 1;
break;
}
return 0;
}
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"reboot", no_argument, 0, 'r'}, {"reboot", no_argument, 0, 'r'},
...@@ -76,8 +52,8 @@ static const struct option my_longopts[] = { ...@@ -76,8 +52,8 @@ static const struct option my_longopts[] = {
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-stop", .progname = "lxc-stop",
.help = "\ .help = "\
--name=NAME\n\ --name=NAME\n\
\n\ \n\
lxc-stop stops a container with the identifier NAME\n\ lxc-stop stops a container with the identifier NAME\n\
...@@ -91,12 +67,40 @@ Options :\n\ ...@@ -91,12 +67,40 @@ Options :\n\
--nolock Avoid using API locks\n\ --nolock Avoid using API locks\n\
--nokill Only request clean shutdown, don't force kill after timeout\n\ --nokill Only request clean shutdown, don't force kill after timeout\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .checker = NULL,
.timeout = -2, .log_priority = "ERROR",
.log_file = "none",
.timeout = -2,
}; };
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 'r':
args->reboot = 1;
break;
case 'W':
args->nowait = 1;
break;
case 't':
if (lxc_safe_long(arg, &args->timeout) < 0)
return -1;
break;
case 'k':
args->hardstop = 1;
break;
case OPT_NO_LOCK:
args->nolock = 1;
break;
case OPT_NO_KILL:
args->nokill = 1;
break;
}
return 0;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct lxc_container *c; struct lxc_container *c;
...@@ -107,18 +111,15 @@ int main(int argc, char *argv[]) ...@@ -107,18 +111,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(ret); exit(ret);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0]; if (lxc_log_init(&log))
exit(ret);
if (lxc_log_init(&log))
exit(ret);
}
/* Set default timeout */ /* Set default timeout */
if (my_args.timeout == -2) { if (my_args.timeout == -2) {
......
...@@ -40,8 +40,8 @@ static const struct option my_longopts[] = { ...@@ -40,8 +40,8 @@ static const struct option my_longopts[] = {
}; };
static struct lxc_arguments my_args = { static struct lxc_arguments my_args = {
.progname = "lxc-unfreeze", .progname = "lxc-unfreeze",
.help = "\ .help = "\
--name=NAME\n\ --name=NAME\n\
\n\ \n\
lxc-unfreeze unfreezes a container with the identifier NAME\n\ lxc-unfreeze unfreezes a container with the identifier NAME\n\
...@@ -49,9 +49,11 @@ lxc-unfreeze unfreezes a container with the identifier NAME\n\ ...@@ -49,9 +49,11 @@ lxc-unfreeze unfreezes a container with the identifier NAME\n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME of the container\n\
--rcfile=FILE Load configuration file FILE\n", --rcfile=FILE Load configuration file FILE\n",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,
.log_priority = "ERROR",
.log_file = "none",
}; };
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -62,18 +64,15 @@ int main(int argc, char *argv[]) ...@@ -62,18 +64,15 @@ int main(int argc, char *argv[])
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* Only create log if explicitly instructed */ log.name = my_args.name;
if (my_args.log_file || my_args.log_priority) { log.file = my_args.log_file;
log.name = my_args.name; log.level = my_args.log_priority;
log.file = my_args.log_file; log.prefix = my_args.progname;
log.level = my_args.log_priority; log.quiet = my_args.quiet;
log.prefix = my_args.progname; log.lxcpath = my_args.lxcpath[0];
log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment