Commit a68e7131 by Jean-Tiare LE BIGOT Committed by Stéphane Graber

clean autodev dir on container exit

When "lxc.autodev = 1", LXC creates automatically a "/dev/.lxc/<name>.<hash>" folder to put container's devices in so that they are visible from both the host and the container itself. On container exit (ne it normal or not), this folder was not cleaned which made "/dev" folder grow continuously. We fix this by adding a new `int lxc_delete_autodev(struct lxc_handler *handler)` called from `static void lxc_fini(const char *name, struct lxc_handler *handler)`. Signed-off-by: 's avatarJean-Tiare LE BIGOT <jean-tiare.le-bigot@ovh.net> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent b682262f
...@@ -291,6 +291,9 @@ static struct caps_opt caps_opt[] = { ...@@ -291,6 +291,9 @@ static struct caps_opt caps_opt[] = {
static struct caps_opt caps_opt[] = {}; static struct caps_opt caps_opt[] = {};
#endif #endif
const char *dev_base_path = "/dev/.lxc";
const char *dev_user_path = "/dev/.lxc/user";
static int run_buffer(char *buffer) static int run_buffer(char *buffer)
{ {
struct lxc_popen_FILE *f; struct lxc_popen_FILE *f;
...@@ -1302,13 +1305,11 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath) ...@@ -1302,13 +1305,11 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
struct stat s; struct stat s;
char tmp_path[MAXPATHLEN]; char tmp_path[MAXPATHLEN];
char fstype[MAX_FSTYPE_LEN]; char fstype[MAX_FSTYPE_LEN];
char *base_path = "/dev/.lxc";
char *user_path = "/dev/.lxc/user";
uint64_t hash; uint64_t hash;
if ( 0 != access(base_path, F_OK) || 0 != stat(base_path, &s) || 0 == S_ISDIR(s.st_mode) ) { if ( 0 != access(dev_base_path, F_OK) || 0 != stat(dev_base_path, &s) || 0 == S_ISDIR(s.st_mode) ) {
/* This is just making /dev/.lxc it better work or we're done */ /* This is just making /dev/.lxc it better work or we're done */
ret = mkdir(base_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); ret = mkdir(dev_base_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if ( ret ) { if ( ret ) {
SYSERROR( "Unable to create /dev/.lxc for autodev" ); SYSERROR( "Unable to create /dev/.lxc for autodev" );
return NULL; return NULL;
...@@ -1342,19 +1343,19 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath) ...@@ -1342,19 +1343,19 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
} }
} }
if ( 0 != access(user_path, F_OK) || 0 != stat(user_path, &s) || 0 == S_ISDIR(s.st_mode) ) { if ( 0 != access(dev_user_path, F_OK) || 0 != stat(dev_user_path, &s) || 0 == S_ISDIR(s.st_mode) ) {
/* /*
* This is making /dev/.lxc/user path for non-priv users. * This is making /dev/.lxc/user path for non-priv users.
* If this doesn't work, we'll have to fall back in the * If this doesn't work, we'll have to fall back in the
* case of non-priv users. It's mode 1777 like /tmp. * case of non-priv users. It's mode 1777 like /tmp.
*/ */
ret = mkdir(user_path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); ret = mkdir(dev_user_path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
if ( ret ) { if ( ret ) {
/* Issue an error but don't fail yet! */ /* Issue an error but don't fail yet! */
ERROR("Unable to create /dev/.lxc/user"); ERROR("Unable to create /dev/.lxc/user");
} }
/* Umask tends to screw us up here */ /* Umask tends to screw us up here */
chmod(user_path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); chmod(dev_user_path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
} }
/* /*
...@@ -1369,18 +1370,18 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath) ...@@ -1369,18 +1370,18 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
hash = fnv_64a_buf(tmp_path, ret, FNV1A_64_INIT); hash = fnv_64a_buf(tmp_path, ret, FNV1A_64_INIT);
ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, base_path, name, hash); ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, dev_base_path, name, hash);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return NULL; return NULL;
if ( 0 != access(tmp_path, F_OK) || 0 != stat(tmp_path, &s) || 0 == S_ISDIR(s.st_mode) ) { if ( 0 != access(tmp_path, F_OK) || 0 != stat(tmp_path, &s) || 0 == S_ISDIR(s.st_mode) ) {
ret = mkdir(tmp_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); ret = mkdir(tmp_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
if ( ret ) { if ( ret ) {
/* Something must have failed with the base_path... /* Something must have failed with the dev_base_path...
* Maybe unpriv user. Try user_path now... */ * Maybe unpriv user. Try dev_user_path now... */
INFO("Setup in /dev/.lxc failed. Trying /dev/.lxc/user." ); INFO("Setup in /dev/.lxc failed. Trying /dev/.lxc/user." );
ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, user_path, name, hash); ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, dev_user_path, name, hash);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return NULL; return NULL;
...@@ -1398,7 +1399,6 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath) ...@@ -1398,7 +1399,6 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
return path; return path;
} }
/* /*
* Do we want to add options for max size of /dev and a file to * Do we want to add options for max size of /dev and a file to
* specify which devices to create? * specify which devices to create?
...@@ -1525,6 +1525,61 @@ static int setup_autodev(const char *root) ...@@ -1525,6 +1525,61 @@ static int setup_autodev(const char *root)
} }
/* /*
* Locate allocated devtmpfs mount and purge it.
* path lookup mostly taken from mk_devtmpfs
*/
int lxc_delete_autodev(struct lxc_handler *handler)
{
int ret;
struct stat s;
struct lxc_conf *lxc_conf = handler->conf;
const char *name = handler->name;
const char *lxcpath = handler->lxcpath;
char tmp_path[MAXPATHLEN];
uint64_t hash;
if ( lxc_conf->autodev <= 0 )
return 0;
/*
* Use the same logic as mk_devtmpfs to compute candidate
* path for cleanup.
*/
ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s", lxcpath, name);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
hash = fnv_64a_buf(tmp_path, ret, FNV1A_64_INIT);
/* Probe /dev/.lxc/<container name>.<hash> */
ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, dev_base_path, name, hash);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
if ( 0 != access(tmp_path, F_OK) || 0 != stat(tmp_path, &s) || 0 == S_ISDIR(s.st_mode) ) {
/* Probe /dev/.lxc/user/<container name>.<hash> */
ret = snprintf(tmp_path, MAXPATHLEN, "%s/%s.%016" PRIx64, dev_user_path, name, hash);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
if ( 0 != access(tmp_path, F_OK) || 0 != stat(tmp_path, &s) || 0 == S_ISDIR(s.st_mode) ) {
WARN("Failed to locate autodev /dev/.lxc and /dev/.lxc/user." );
return -1;
}
}
/* Do the cleanup */
INFO("Cleaning %s", tmp_path );
if ( 0 != lxc_rmdir_onedev(tmp_path, NULL) ) {
ERROR("Failed to cleanup autodev" );
}
return 0;
}
/*
* I'll forgive you for asking whether all of this is needed :) The * I'll forgive you for asking whether all of this is needed :) The
* answer is yes. * answer is yes.
* pivot_root will fail if the new root, the put_old dir, or the parent * pivot_root will fail if the new root, the put_old dir, or the parent
......
...@@ -377,6 +377,7 @@ extern int lxc_clear_automounts(struct lxc_conf *c); ...@@ -377,6 +377,7 @@ extern int lxc_clear_automounts(struct lxc_conf *c);
extern int lxc_clear_hooks(struct lxc_conf *c, const char *key); extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
extern int lxc_clear_idmaps(struct lxc_conf *c); extern int lxc_clear_idmaps(struct lxc_conf *c);
extern int lxc_clear_groups(struct lxc_conf *c); extern int lxc_clear_groups(struct lxc_conf *c);
extern int lxc_delete_autodev(struct lxc_handler *handler);
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name, extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
const char *lxcpath); const char *lxcpath);
......
...@@ -477,6 +477,7 @@ static void lxc_fini(const char *name, struct lxc_handler *handler) ...@@ -477,6 +477,7 @@ static void lxc_fini(const char *name, struct lxc_handler *handler)
lxc_console_delete(&handler->conf->console); lxc_console_delete(&handler->conf->console);
lxc_delete_tty(&handler->conf->tty_info); lxc_delete_tty(&handler->conf->tty_info);
lxc_delete_autodev(handler);
close(handler->conf->maincmd_fd); close(handler->conf->maincmd_fd);
handler->conf->maincmd_fd = -1; handler->conf->maincmd_fd = -1;
free(handler->name); free(handler->name);
......
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