Skip to content

Commit

Permalink
lxc-destroy: remove btrfs subvolumes
Browse files Browse the repository at this point in the history
Doing this requires some btrfs functions from bdev to be used in
utils.c  Because utils.h is imported by lxc_init.c, I had to create
a new initutils.[ch] which are used by both lxc_init.c and utils.c
We could instead put the btrfs functions into utils.c, which would
be a shorter patch, but it really doesn't belong there.  So I went
the other way figuring there may be more such cases coming up of
fns in utils.c needing code from bdev.c which can't go into lxc_init.

Currently, if we detect a btrfs subvolume we just remove it.  The
st_dev on that dir is different, so we cannot detect if this is
bound in from another fs easily.  If we care, we should check
whether this is a mountpoint, this patch doesn't do that.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
  • Loading branch information
hallyn authored and stgraber committed Aug 28, 2015
1 parent f8b444f commit 44b58fe
Show file tree
Hide file tree
Showing 8 changed files with 372 additions and 310 deletions.
2 changes: 2 additions & 0 deletions src/lxc/Makefile.am
Expand Up @@ -12,6 +12,7 @@ noinst_HEADERS = \
conf.h \
console.h \
error.h \
initutils.h \
list.h \
log.h \
lxc.h \
Expand Down Expand Up @@ -66,6 +67,7 @@ liblxc_so_SOURCES = \
cgfs.c \
cgroup.c cgroup.h \
lxc.h \
initutils.c initutils.h \
utils.c utils.h \
sync.c sync.h \
namespace.h namespace.c \
Expand Down
11 changes: 9 additions & 2 deletions src/lxc/bdev.c
Expand Up @@ -1265,7 +1265,7 @@ int btrfs_list_get_path_rootid(int fd, u64 *treeid)
return 0;
}

static bool is_btrfs_fs(const char *path)
bool is_btrfs_fs(const char *path)
{
int fd, ret;
struct btrfs_ioctl_space_args sargs;
Expand Down Expand Up @@ -1543,7 +1543,7 @@ static int btrfs_do_destroy_subvol(const char *path)

fd = open(newfull, O_RDONLY);
if (fd < 0) {
ERROR("Error opening %s", newfull);
SYSERROR("Error opening %s", newfull);
free(newfull);
return -1;
}
Expand Down Expand Up @@ -1841,6 +1841,13 @@ static int btrfs_recursive_destroy(const char *path)
return btrfs_do_destroy_subvol(path);
}

bool btrfs_try_remove_subvol(const char *path)
{
if (!btrfs_detect(path))
return false;
return btrfs_recursive_destroy(path) == 0;
}

static int btrfs_destroy(struct bdev *orig)
{
return btrfs_recursive_destroy(orig->src);
Expand Down
26 changes: 0 additions & 26 deletions src/lxc/bdev.h
Expand Up @@ -123,30 +123,4 @@ struct bdev *bdev_create(const char *dest, const char *type,
void bdev_put(struct bdev *bdev);

bool rootfs_is_blockdev(struct lxc_conf *conf);

/* define constants if the kernel/glibc headers don't define them */
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif

#ifndef MS_REC
#define MS_REC 16384
#endif

#ifndef MNT_DETACH
#define MNT_DETACH 2
#endif

#ifndef MS_SLAVE
#define MS_SLAVE (1<<19)
#endif

#ifndef MS_RELATIME
#define MS_RELATIME (1 << 21)
#endif

#ifndef MS_STRICTATIME
#define MS_STRICTATIME (1 << 24)
#endif

#endif
293 changes: 293 additions & 0 deletions src/lxc/initutils.c
@@ -0,0 +1,293 @@
/*
* lxc: linux Container library
*
* (C) Copyright IBM Corp. 2007, 2008
*
* Authors:
* Daniel Lezcano <daniel.lezcano at free.fr>
*
* This library is free software; you can redistribute it and/or
* 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
*/

#include "initutils.h"
#include "log.h"

lxc_log_define(lxc_initutils, lxc);

static int mount_fs(const char *source, const char *target, const char *type)
{
/* the umount may fail */
if (umount(target))
WARN("failed to unmount %s : %s", target, strerror(errno));

if (mount(source, target, type, 0, NULL)) {
ERROR("failed to mount %s : %s", target, strerror(errno));
return -1;
}

DEBUG("'%s' mounted on '%s'", source, target);

return 0;
}

extern void lxc_setup_fs(void)
{
if (mount_fs("proc", "/proc", "proc"))
INFO("failed to remount proc");

/* if we can't mount /dev/shm, continue anyway */
if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
INFO("failed to mount /dev/shm");

/* If we were able to mount /dev/shm, then /dev exists */
/* Sure, but it's read-only per config :) */
if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
DEBUG("failed to create '/dev/mqueue'");
return;
}

/* continue even without posix message queue support */
if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
INFO("failed to mount /dev/mqueue");
}

static char *copy_global_config_value(char *p)
{
int len = strlen(p);
char *retbuf;

if (len < 1)
return NULL;
if (p[len-1] == '\n') {
p[len-1] = '\0';
len--;
}
retbuf = malloc(len+1);
if (!retbuf)
return NULL;
strcpy(retbuf, p);
return retbuf;
}

const char *lxc_global_config_value(const char *option_name)
{
static const char * const options[][2] = {
{ "lxc.bdev.lvm.vg", DEFAULT_VG },
{ "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
{ "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
{ "lxc.lxcpath", NULL },
{ "lxc.default_config", NULL },
{ "lxc.cgroup.pattern", NULL },
{ "lxc.cgroup.use", NULL },
{ NULL, NULL },
};

/* placed in the thread local storage pool for non-bionic targets */
#ifdef HAVE_TLS
static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
#else
static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
#endif

/* user_config_path is freed as soon as it is used */
char *user_config_path = NULL;

/*
* The following variables are freed at bottom unconditionally.
* So NULL the value if it is to be returned to the caller
*/
char *user_default_config_path = NULL;
char *user_lxc_path = NULL;
char *user_cgroup_pattern = NULL;

if (geteuid() > 0) {
const char *user_home = getenv("HOME");
if (!user_home)
user_home = "/";

user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));

sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
user_cgroup_pattern = strdup("lxc/%n");
}
else {
user_config_path = strdup(LXC_GLOBAL_CONF);
user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
user_lxc_path = strdup(LXCPATH);
user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
}

const char * const (*ptr)[2];
size_t i;
char buf[1024], *p, *p2;
FILE *fin = NULL;

for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
if (!strcmp(option_name, (*ptr)[0]))
break;
}
if (!(*ptr)[0]) {
free(user_config_path);
free(user_default_config_path);
free(user_lxc_path);
free(user_cgroup_pattern);
errno = EINVAL;
return NULL;
}

if (values[i]) {
free(user_config_path);
free(user_default_config_path);
free(user_lxc_path);
free(user_cgroup_pattern);
return values[i];
}

fin = fopen_cloexec(user_config_path, "r");
free(user_config_path);
if (fin) {
while (fgets(buf, 1024, fin)) {
if (buf[0] == '#')
continue;
p = strstr(buf, option_name);
if (!p)
continue;
/* see if there was just white space in front
* of the option name
*/
for (p2 = buf; p2 < p; p2++) {
if (*p2 != ' ' && *p2 != '\t')
break;
}
if (p2 < p)
continue;
p = strchr(p, '=');
if (!p)
continue;
/* see if there was just white space after
* the option name
*/
for (p2 += strlen(option_name); p2 < p; p2++) {
if (*p2 != ' ' && *p2 != '\t')
break;
}
if (p2 < p)
continue;
p++;
while (*p && (*p == ' ' || *p == '\t')) p++;
if (!*p)
continue;

if (strcmp(option_name, "lxc.lxcpath") == 0) {
free(user_lxc_path);
user_lxc_path = copy_global_config_value(p);
remove_trailing_slashes(user_lxc_path);
values[i] = user_lxc_path;
user_lxc_path = NULL;
goto out;
}

values[i] = copy_global_config_value(p);
goto out;
}
}
/* could not find value, use default */
if (strcmp(option_name, "lxc.lxcpath") == 0) {
remove_trailing_slashes(user_lxc_path);
values[i] = user_lxc_path;
user_lxc_path = NULL;
}
else if (strcmp(option_name, "lxc.default_config") == 0) {
values[i] = user_default_config_path;
user_default_config_path = NULL;
}
else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
values[i] = user_cgroup_pattern;
user_cgroup_pattern = NULL;
}
else
values[i] = (*ptr)[1];

/* special case: if default value is NULL,
* and there is no config, don't view that
* as an error... */
if (!values[i])
errno = 0;

out:
if (fin)
fclose(fin);

free(user_cgroup_pattern);
free(user_default_config_path);
free(user_lxc_path);

return values[i];
}

extern void remove_trailing_slashes(char *p)
{
int l = strlen(p);
while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
p[l] = '\0';
}

FILE *fopen_cloexec(const char *path, const char *mode)
{
int open_mode = 0;
int step = 0;
int fd;
int saved_errno = 0;
FILE *ret;

if (!strncmp(mode, "r+", 2)) {
open_mode = O_RDWR;
step = 2;
} else if (!strncmp(mode, "r", 1)) {
open_mode = O_RDONLY;
step = 1;
} else if (!strncmp(mode, "w+", 2)) {
open_mode = O_RDWR | O_TRUNC | O_CREAT;
step = 2;
} else if (!strncmp(mode, "w", 1)) {
open_mode = O_WRONLY | O_TRUNC | O_CREAT;
step = 1;
} else if (!strncmp(mode, "a+", 2)) {
open_mode = O_RDWR | O_CREAT | O_APPEND;
step = 2;
} else if (!strncmp(mode, "a", 1)) {
open_mode = O_WRONLY | O_CREAT | O_APPEND;
step = 1;
}
for (; mode[step]; step++)
if (mode[step] == 'x')
open_mode |= O_EXCL;
open_mode |= O_CLOEXEC;

fd = open(path, open_mode, 0666);
if (fd < 0)
return NULL;

ret = fdopen(fd, mode);
saved_errno = errno;
if (!ret)
close(fd);
errno = saved_errno;
return ret;
}

0 comments on commit 44b58fe

Please sign in to comment.