* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
+#include "../include/netns_ifaddrs.h"
#include "af_unix.h"
+#include "api_extensions.h"
#include "attach.h"
#include "cgroup.h"
#include "commands.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
+#include "raw_syscalls.h"
#include "start.h"
#include "state.h"
#include "storage.h"
#include "storage/overlay.h"
#include "storage_utils.h"
#include "sync.h"
+#include "syscall_wrappers.h"
#include "terminal.h"
#include "utils.h"
#include "version.h"
#include <sys/mkdev.h>
#endif
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
#if IS_BIONIC
#include <../include/lxcmntent.h>
#else
if (ret < 0 || (size_t)ret >= len)
return -1;
- if (!file_exists(path))
- return 0;
+ fd = open(path, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ if (errno != ENOENT)
+ return -1;
- fd = open(path, O_RDWR);
- if (fd < 0)
return 0;
+ }
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_pid = 0;
ret = fcntl(fd, F_OFD_GETLK, &lk);
- if (ret < 0 && errno == EINVAL)
+ if (ret < 0 && errno == EINVAL) {
ret = flock(fd, LOCK_EX | LOCK_NB);
+ if (ret < 0 && errno == EWOULDBLOCK)
+ ret = 0;
+ }
close(fd);
if (ret < 0 || (size_t)ret >= len)
return -1;
- fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0755);
+ fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
if (fd < 0)
return -1;
if (!c)
return false;
- ret = lxc_freeze(c->name, c->config_path);
+ ret = lxc_freeze(c->lxc_conf, c->name, c->config_path);
if (ret < 0)
return false;
if (!c)
return false;
- ret = lxc_unfreeze(c->name, c->config_path);
+ ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path);
if (ret < 0)
return false;
{
int ret;
+ if (!c)
+ return -EINVAL;
+
ret = lxc_cmd_console_log(c->name, do_lxcapi_get_config_path(c), log);
if (ret < 0) {
if (ret == -ENODATA)
/* We don't really care if this doesn't print all the
* characters. All that it means is that the proctitle will be
* ugly. Similarly, we also don't care if setproctitle() fails.
- * */
- (void)snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
- INFO("Attempting to set proc title to %s", title);
- (void)setproctitle(title);
+ */
+ ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
+ if (ret > 0) {
+ ret = setproctitle(title);
+ if (ret < 0)
+ INFO("Failed to set process title to %s", title);
+ else
+ INFO("Set process title to %s", title);
+ }
/* We fork() a second time to be reparented to init. Like
* POSIX's daemon() function we change to "/" and redirect
ret = setsid();
if (ret < 0)
TRACE("Process %d is already process group leader", lxc_raw_getpid());
- } else {
- if (!am_single_threaded()) {
- ERROR("Cannot start non-daemonized container when threaded");
- free_init_cmd(init_cmd);
- lxc_free_handler(handler);
- return false;
- }
+ } else if (!am_single_threaded()) {
+ ERROR("Cannot start non-daemonized container when threaded");
+ free_init_cmd(init_cmd);
+ lxc_free_handler(handler);
+ return false;
}
- /* We need to write PID file after daemonize, so we always
- * write the right PID.
+ /* We need to write PID file after daemonize, so we always write the
+ * right PID.
*/
if (c->pidfile) {
int ret, w;
- char pidstr[LXC_NUMSTRLEN64];
+ char pidstr[INTTYPE_TO_STRLEN(pid_t)];
- w = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", (int)lxc_raw_getpid());
- if (w < 0 || (size_t)w >= LXC_NUMSTRLEN64) {
+ w = snprintf(pidstr, sizeof(pidstr), "%d", lxc_raw_getpid());
+ if (w < 0 || (size_t)w >= sizeof(pidstr)) {
free_init_cmd(init_cmd);
lxc_free_handler(handler);
free_init_cmd(init_cmd);
lxc_free_handler(handler);
- SYSERROR("Failed to write '%s'", c->pidfile);
+ SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile);
if (c->daemonize)
_exit(EXIT_FAILURE);
if (conf->monitor_unshare) {
ret = unshare(CLONE_NEWNS);
if (ret < 0) {
- SYSERROR("failed to unshare mount namespace");
+ SYSERROR("Failed to unshare mount namespace");
lxc_free_handler(handler);
ret = 1;
goto on_error;
if (pid == 0) { /* child */
int ret = 1, nbytes;
- struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+ struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
/* close the read-end of the pipe */
close(pipefd[0]);
}
/* Grab the list of interfaces */
- if (getifaddrs(&interfaceArray)) {
+ if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
SYSERROR("Failed to get interfaces list");
goto out;
}
out:
if (interfaceArray)
- freeifaddrs(interfaceArray);
+ netns_freeifaddrs(interfaceArray);
/* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]);
int ret = 1;
char *address = NULL;
void *tempAddrPtr = NULL;
- struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+ struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
/* close the read-end of the pipe */
close(pipefd[0]);
}
/* Grab the list of interfaces */
- if (getifaddrs(&interfaceArray)) {
+ if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
SYSERROR("Failed to get interfaces list");
goto out;
}
if (tempIfAddr->ifa_addr == NULL)
continue;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
if (tempIfAddr->ifa_addr->sa_family == AF_INET) {
if (family && strcmp(family, "inet"))
continue;
tempAddrPtr = &((struct sockaddr_in6 *)tempIfAddr->ifa_addr)->sin6_addr;
}
+#pragma GCC diagnostic pop
+
if (interface && strcmp(interface, tempIfAddr->ifa_name))
continue;
else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0)
out:
if (interfaceArray)
- freeifaddrs(interfaceArray);
+ netns_freeifaddrs(interfaceArray);
/* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]);
return false;
fd = open(alt_file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (fd < 0)
goto on_error;
struct stat fbuf;
void *buf = NULL;
char *del = NULL;
- char path[MAXPATHLEN];
- char newpath[MAXPATHLEN];
+ char path[PATH_MAX];
+ char newpath[PATH_MAX];
int fd, ret, n = 0, v = 0;
bool bret = false;
size_t len = 0, bytes = 0;
if (container_disk_lock(c0))
return false;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
+ if (ret < 0 || ret > PATH_MAX)
goto out;
- ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ ret = snprintf(newpath, PATH_MAX, "%s\n%s\n", c->config_path, c->name);
+ if (ret < 0 || ret > PATH_MAX)
goto out;
/* If we find an lxc-snapshot file using the old format only listing the
void mod_all_rdeps(struct lxc_container *c, bool inc)
{
struct lxc_container *p;
- char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
+ char *lxcpath = NULL, *lxcname = NULL, path[PATH_MAX];
size_t pathlen = 0, namelen = 0;
FILE *f;
int ret;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends",
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends",
c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("Path name too long");
return;
}
static bool has_fs_snapshots(struct lxc_container *c)
{
FILE *f;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
int ret, v;
struct stat fbuf;
bool bret = false;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c->config_path,
c->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ if (ret < 0 || ret > PATH_MAX)
goto out;
/* If the file doesn't exist there are no snapshots. */
static bool has_snapshots(struct lxc_container *c)
{
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct dirent *direntp;
int count=0;
DIR *dir;
}
}
+ /* LXC is not managing the storage of the container. */
+ if (conf && !conf->rootfs.managed)
+ goto on_success;
+
if (conf && conf->rootfs.path && conf->rootfs.mount) {
if (!do_destroy_container(conf)) {
ERROR("Error destroying rootfs for %s", c->name);
}
INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name);
+on_success:
bret = true;
out:
if (!c || !lxcapi_is_defined(c))
return false;
- if (has_snapshots(c)) {
- ERROR("Container %s has snapshots; not removing", c->name);
- return false;
- }
+ if (c->lxc_conf && c->lxc_conf->rootfs.managed) {
+ if (has_snapshots(c)) {
+ ERROR("Container %s has snapshots; not removing", c->name);
+ return false;
+ }
- if (has_fs_snapshots(c)) {
- ERROR("container %s has snapshots on its rootfs", c->name);
- return false;
+ if (has_fs_snapshots(c)) {
+ ERROR("container %s has snapshots on its rootfs", c->name);
+ return false;
+ }
}
return container_destroy(c, NULL);
if (is_stopped(c))
return false;
- cgroup_ops = cgroup_init(NULL);
+ cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops)
return false;
- if (container_disk_lock(c))
- return false;
-
ret = cgroup_ops->set(cgroup_ops, subsys, value, c->name, c->config_path);
- container_disk_unlock(c);
-
cgroup_exit(cgroup_ops);
return ret == 0;
if (is_stopped(c))
return -1;
- cgroup_ops = cgroup_init(NULL);
+ cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops)
return -1;
- if (container_disk_lock(c))
- return -1;
-
ret = cgroup_ops->get(cgroup_ops, subsys, retv, inlen, c->name,
c->config_path);
- container_disk_unlock(c);
-
cgroup_exit(cgroup_ops);
return ret;
lxc_list_for_each(it, &c->lxc_conf->hooks[i]) {
char *hookname = it->elem;
char *fname = strrchr(hookname, '/');
- char tmppath[MAXPATHLEN];
+ char tmppath[PATH_MAX];
if (!fname) /* relative path - we don't support, but maybe we should */
return 0;
}
/* copy the script, and change the entry in confile */
- ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
+ ret = snprintf(tmppath, PATH_MAX, "%s/%s/%s",
c->config_path, c->name, fname+1);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
ret = copy_file(it->elem, tmppath);
static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
{
- char newpath[MAXPATHLEN];
+ char newpath[PATH_MAX];
char *oldpath = oldc->lxc_conf->fstab;
int ret;
if (!p)
return -1;
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s",
+ ret = snprintf(newpath, PATH_MAX, "%s/%s%s",
c->config_path, c->name, p);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("error printing new path for %s", oldpath);
return -1;
}
static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
{
- char path0[MAXPATHLEN], path1[MAXPATHLEN];
+ char path0[PATH_MAX], path1[PATH_MAX];
int ret;
- ret = snprintf(path0, MAXPATHLEN, "%s/%s/lxc_rdepends", c0->config_path,
+ ret = snprintf(path0, PATH_MAX, "%s/%s/lxc_rdepends", c0->config_path,
c0->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
WARN("Error copying reverse dependencies");
return;
}
- ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+ ret = snprintf(path1, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
c->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
WARN("Error copying reverse dependencies");
return;
}
static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
{
int ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
FILE *f;
bool bret;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return false;
f = fopen(path, "a");
int flags = data->flags;
char **hookargs = data->hookargs;
int ret = -1;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct lxc_storage *bdev;
FILE *fout;
struct lxc_conf *conf = c->lxc_conf;
}
if (!(flags & LXC_CLONE_KEEPNAME)) {
- ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
+ ret = snprintf(path, PATH_MAX, "%s/etc/hostname", bdev->dest);
storage_put(bdev);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
if (!file_exists(path))
const char *bdevtype, const char *bdevdata, uint64_t newsize,
char **hookargs)
{
- char newpath[MAXPATHLEN];
+ char newpath[PATH_MAX];
int fd, ret;
struct clone_update_data data;
size_t saved_unexp_len;
if (container_mem_lock(c))
return NULL;
-
- if (!is_stopped(c)) {
- ERROR("error: Original container (%s) is running", c->name);
+ if (!is_stopped(c) && !(flags & LXC_CLONE_ALLOW_RUNNING)) {
+ ERROR("error: Original container (%s) is running. Use --allowrunning if you want to force a snapshot of the running container.", c->name);
goto out;
}
if (!lxcpath)
lxcpath = do_lxcapi_get_config_path(c);
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(newpath, PATH_MAX, "%s/%s/config", lxcpath, newname);
+ if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("clone: failed making config pathname");
goto out;
}
}
fd = open(newpath, O_WRONLY | O_CREAT | O_CLOEXEC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (fd < 0) {
SYSERROR("Failed to open \"%s\"", newpath);
goto out;
saved_unexp_conf = NULL;
c->lxc_conf->unexpanded_len = saved_unexp_len;
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s/rootfs", lxcpath, newname);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(newpath, PATH_MAX, "%s/%s/rootfs", lxcpath, newname);
+ if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("clone: failed making rootfs pathname");
goto out;
}
* If the old style snapshot path exists, use it
* /var/lib/lxc -> /var/lib/lxcsnaps
*/
- ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%ssnaps", c->config_path);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
if (dir_exists(snappath)) {
- ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%ssnaps/%s", c->config_path, c->name);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
return true;
* Use the new style path
* /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0
*/
- ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%s/%s/snaps", c->config_path, c->name);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
return true;
time_t timer;
struct tm tm_info;
struct lxc_container *c2;
- char snappath[MAXPATHLEN], newname[20];
+ char snappath[PATH_MAX], newname[20];
char buffer[25];
FILE *f;
static char *get_timestamp(char* snappath, char *name)
{
- char path[MAXPATHLEN], *s = NULL;
+ char path[PATH_MAX], *s = NULL;
int ret, len;
FILE *fin;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s/ts", snappath, name);
+ if (ret < 0 || ret >= PATH_MAX)
return NULL;
fin = fopen(path, "r");
static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
{
- char snappath[MAXPATHLEN], path2[MAXPATHLEN];
+ char snappath[PATH_MAX], path2[PATH_MAX];
int count = 0, ret;
struct dirent *direntp;
struct lxc_snapshot *snaps =NULL, *nsnaps;
if (!strcmp(direntp->d_name, ".."))
continue;
- ret = snprintf(path2, MAXPATHLEN, "%s/%s/config", snappath, direntp->d_name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(path2, PATH_MAX, "%s/%s/config", snappath, direntp->d_name);
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("pathname too long");
goto out_free;
}
static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
int flags = 0;
struct lxc_container *snap, *rest;
struct lxc_storage *bdev;
static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
if (!c || !c->name || !c->config_path || !snapname)
return false;
static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
if (!c || !c->name || !c->config_path)
return false;
static bool do_lxcapi_may_control(struct lxc_container *c)
{
+ if (!c)
+ return false;
+
return lxc_try_cmd(c->name, c->config_path) == 0;
}
int ret;
char *tmp;
pid_t pid;
- char chrootpath[MAXPATHLEN];
+ char chrootpath[PATH_MAX];
char *directory_path = NULL;
pid = fork();
}
/* prepare the path */
- ret = snprintf(chrootpath, MAXPATHLEN, "/proc/%d/root", init_pid);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(chrootpath, PATH_MAX, "/proc/%d/root", init_pid);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
ret = chroot(chrootpath);
struct lxc_mount *mnt)
{
char *suff, *sret;
- char template[MAXPATHLEN], path[MAXPATHLEN];
+ char template[PATH_MAX], path[PATH_MAX];
pid_t pid, init_pid;
struct stat sb;
int ret = -1, fd = -EBADF;
{
return !!lxc_get_config(key);
}
+
+bool lxc_has_api_extension(const char *extension)
+{
+ /* The NULL API extension is always present. :) */
+ if (!extension)
+ return true;
+
+ for (size_t i = 0; i < nr_api_extensions; i++)
+ if (strcmp(api_extensions[i], extension) == 0)
+ return true;
+
+ return false;
+}