#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
+#include <sys/param.h>
#include <lxc/lxccontainer.h>
struct lxc_arguments;
#define LXC_COMMON_OPTIONS \
{ "name", required_argument, 0, 'n' }, \
- { "help", no_argument, 0, 'h' }, \
+ { "help", no_argument, 0, 'h' }, \
{ "usage", no_argument, 0, OPT_USAGE }, \
{ "version", no_argument, 0, OPT_VERSION }, \
{ "quiet", no_argument, 0, 'q' }, \
extern int lxc_arguments_str_to_int(struct lxc_arguments *args,
const char *str);
-#define lxc_error(arg, fmt, args...) \
- if (!(arg)->quiet) \
- fprintf(stderr, "%s: " fmt "\n", (arg)->progname, ##args)
-
extern bool lxc_setup_shared_ns(struct lxc_arguments *args, struct lxc_container *c);
+/* Helper macro to define errno string. */
+#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE) || IS_BIONIC
+#define lxc_log_strerror_r \
+ char errno_buf[MAXPATHLEN / 2] = {"Failed to get errno string"}; \
+ char *ptr = errno_buf; \
+ { \
+ (void)strerror_r(errno, errno_buf, sizeof(errno_buf)); \
+ }
+#else
+#define lxc_log_strerror_r \
+ char errno_buf[MAXPATHLEN / 2] = {"Failed to get errno string"}; \
+ char *ptr; \
+ { \
+ ptr = strerror_r(errno, errno_buf, sizeof(errno_buf)); \
+ if (!ptr) \
+ ptr = errno_buf; \
+ }
+#endif
+
+#define lxc_info(arg, fmt, args...) \
+ do { \
+ if (!(arg)->quiet) { \
+ fprintf(stdout, "%s: " fmt "\n", (arg)->progname, ##args); \
+ } \
+ } while (0)
+
+#define lxc_error(arg, fmt, args...) \
+ do { \
+ if (!(arg)->quiet) { \
+ fprintf(stderr, "%s: " fmt "\n", (arg)->progname, ##args); \
+ } \
+ } while (0)
+
+#define lxc_sys_error(arg, fmt, args...) \
+ do { \
+ if (!(arg)->quiet) { \
+ lxc_log_strerror_r \
+ fprintf(stderr, "%s: %s - " fmt "\n", (arg)->progname, ptr, ##args); \
+ } \
+ } while (0)
+
#endif /* __LXC_ARGUMENTS_H */
return 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)
{
char **it;
char *del;
return false;
}
-int lxc_attach_create_log_file(const char *log_file)
+static int lxc_attach_create_log_file(const char *log_file)
{
int fd;
fd = open(log_file, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600);
if (fd < 0) {
- fprintf(stderr, "Failed to open log file \"%s\"\n", log_file);
+ lxc_error(&my_args, "Failed to open log file \"%s\"", log_file);
return -1;
}
if (geteuid()) {
if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
- if (!my_args.quiet)
- fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+ lxc_error(&my_args, "You lack access to %s", my_args.lxcpath[0]);
exit(EXIT_FAILURE);
}
}
if (my_args.rcfile) {
c->clear_config(c);
if (!c->load_config(c, my_args.rcfile)) {
- fprintf(stderr, "Failed to load rcfile\n");
+ lxc_error(&my_args, "Failed to load rcfile");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
+
c->configfile = strdup(my_args.rcfile);
if (!c->configfile) {
- fprintf(stderr, "Out of memory setting new config filename\n");
+ lxc_error(&my_args, "Out of memory setting new config filename");
lxc_container_put(c);
exit(EXIT_FAILURE);
}
}
if (!c->may_control(c)) {
- fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+ lxc_error(&my_args, "Insufficent privileges to control %s", c->name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (remount_sys_proc)
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
+
if (elevated_privileges)
attach_options.attach_flags &= ~(elevated_privileges);
+
if (stdfd_is_pty())
attach_options.attach_flags |= LXC_ATTACH_TERMINAL;
+
attach_options.namespaces = namespace_flags;
attach_options.personality = new_personality;
attach_options.env_policy = env_policy;
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
else
ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
-
if (ret < 0)
goto out;
lxc_container_put(c);
if (ret >= 0)
exit(wexit);
+
exit(EXIT_FAILURE);
}
static struct lxc_list defines;
-static int ensure_path(char **confpath, const char *path)
+static int ensure_path(struct lxc_arguments *args, char **confpath, const char *path)
{
int err = -1, fd;
char *fullpath = NULL;
if (access(path, W_OK)) {
fd = creat(path, 0600);
if (fd < 0 && errno != EEXIST) {
- fprintf(stderr, "failed to create '%s'\n", path);
+ lxc_error(args, "Failed to create '%s'", path);
goto err;
}
+
if (fd >= 0)
close(fd);
}
fullpath = realpath(path, NULL);
if (!fullpath) {
- fprintf(stderr, "failed to get the real path of '%s'\n", path);
+ lxc_error(args, "Failed to get the real path of '%s'", path);
goto err;
}
*confpath = fullpath;
}
+
err = EXIT_SUCCESS;
err:
lxcpath = my_args.lxcpath[0];
if (access(lxcpath, O_RDONLY) < 0) {
- if (!my_args.quiet)
- fprintf(stderr, "You lack access to %s\n", lxcpath);
+ lxc_error(&my_args, "You lack access to %s", lxcpath);
exit(err);
}
/* rcfile is specified in the cli option */
if (my_args.rcfile) {
rcfile = (char *)my_args.rcfile;
+
c = lxc_container_new(my_args.name, lxcpath);
if (!c) {
- fprintf(stderr, "Failed to create lxc_container\n");
+ lxc_error(&my_args, "Failed to create lxc_container");
exit(err);
}
+
c->clear_config(c);
+
if (!c->load_config(c, rcfile)) {
- fprintf(stderr, "Failed to load rcfile\n");
+ lxc_error(&my_args, "Failed to load rcfile");
lxc_container_put(c);
exit(err);
}
+
c->configfile = strdup(my_args.rcfile);
if (!c->configfile) {
- fprintf(stderr, "Out of memory setting new config filename\n");
+ lxc_error(&my_args, "Out of memory setting new config filename");
goto out;
}
} else {
rc = asprintf(&rcfile, "%s/%s/config", lxcpath, my_args.name);
if (rc == -1) {
- fprintf(stderr, "failed to allocate memory\n");
+ lxc_error(&my_args, "Failed to allocate memory");
exit(err);
}
free(rcfile);
rcfile = NULL;
}
+
c = lxc_container_new(my_args.name, lxcpath);
if (!c) {
- fprintf(stderr, "Failed to create lxc_container\n");
+ lxc_error(&my_args, "Failed to create lxc_container");
exit(err);
}
}
* to be created for it to be started. You can just pass a configuration
* file as argument and start the container right away.
*/
-
if (!c->may_control(c)) {
- fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+ lxc_error(&my_args, "Insufficent privileges to control %s", c->name);
goto out;
}
if (c->is_running(c)) {
- fprintf(stderr, "Container is already running.\n");
+ lxc_error(&my_args, "Container is already running.");
err = EXIT_SUCCESS;
goto out;
}
+
/*
* We should use set_config_item() over &defines, which would handle
* unset c->lxc_conf for us and let us not use lxc_config_define_load()
*/
if (!c->lxc_conf) {
- fprintf(stderr, "No container config specified\n");
+ lxc_error(&my_args, "No container config specified");
goto out;
}
goto out;
if (!rcfile && !strcmp("/sbin/init", args[0])) {
- fprintf(stderr, "Executing '/sbin/init' with no configuration file may crash the host\n");
+ lxc_error(&my_args, "Executing '/sbin/init' with no configuration file may crash the host");
goto out;
}
if (my_args.pidfile != NULL) {
- if (ensure_path(&c->pidfile, my_args.pidfile) < 0) {
- fprintf(stderr, "failed to ensure pidfile '%s'\n", my_args.pidfile);
+ if (ensure_path(&my_args, &c->pidfile, my_args.pidfile) < 0) {
+ lxc_error(&my_args, "Failed to ensure pidfile '%s'", my_args.pidfile);
goto out;
}
}
err = c->start(c, 0, NULL) ? EXIT_SUCCESS : EXIT_FAILURE;
else
err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE;
-
if (err) {
- fprintf(stderr, "The container failed to start.\n");
+ lxc_error(&my_args, "The container failed to start.");
+
if (my_args.daemonize)
- fprintf(stderr, "To get more details, run the container in foreground mode.\n");
- fprintf(stderr, "Additional information can be obtained by setting the "
- "--logfile and --logpriority options.\n");
+ lxc_error(&my_args, "To get more details, run the container in foreground mode.");
+
+ lxc_error(&my_args, "Additional information can be obtained by setting the "
+ "--logfile and --logpriority options.\n");
+
err = c->error_num;
lxc_container_put(c);
exit(err);
/* some checks */
if (!my_args.hardstop && my_args.timeout < -1) {
- fprintf(stderr, "invalid timeout\n");
+ lxc_error(&my_args, "Invalid timeout");
exit(ret);
}
if (my_args.hardstop && my_args.nokill) {
- fprintf(stderr, "-k can't be used with --nokill\n");
+ lxc_error(&my_args, "-k can't be used with --nokill");
exit(ret);
}
if (my_args.hardstop && my_args.reboot) {
- fprintf(stderr, "-k can't be used with -r\n");
+ lxc_error(&my_args, "-k can't be used with -r");
exit(ret);
}
if (my_args.hardstop && my_args.timeout) {
- fprintf(stderr, "-k doesn't allow timeouts\n");
+ lxc_error(&my_args, "-k doesn't allow timeouts");
exit(ret);
}
if (my_args.nolock && !my_args.hardstop) {
- fprintf(stderr, "--nolock may only be used with -k\n");
+ lxc_error(&my_args, "--nolock may only be used with -k");
exit(ret);
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
- fprintf(stderr, "Error opening container\n");
+ lxc_error(&my_args, "Error opening container");
goto out;
}
if (my_args.rcfile) {
c->clear_config(c);
+
if (!c->load_config(c, my_args.rcfile)) {
- fprintf(stderr, "Failed to load rcfile\n");
+ lxc_error(&my_args, "Failed to load rcfile");
goto out;
}
+
c->configfile = strdup(my_args.rcfile);
if (!c->configfile) {
- fprintf(stderr, "Out of memory setting new config filename\n");
+ lxc_error(&my_args, "Out of memory setting new config filename");
goto out;
}
}
if (!c->may_control(c)) {
- fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+ lxc_error(&my_args, "Insufficent privileges to control %s", c->name);
goto out;
}
if (!c->is_running(c)) {
- fprintf(stderr, "%s is not running\n", c->name);
+ lxc_error(&my_args, "%s is not running", c->name);
+
/* Per our manpage we need to exit with exit code:
* 2: The specified container exists but was not running.
*/
ret = EXIT_FAILURE;
else
ret = EXIT_SUCCESS;
+
goto out;
}