]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
clean autodev dir on container exit
authorJean-Tiare LE BIGOT <jean-tiare.le-bigot@ovh.net>
Wed, 13 Aug 2014 08:30:04 +0000 (10:30 +0200)
committerStéphane Graber <stgraber@ubuntu.com>
Sat, 16 Aug 2014 01:07:21 +0000 (21:07 -0400)
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: Jean-Tiare LE BIGOT <jean-tiare.le-bigot@ovh.net>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/start.c

index 531a588ad3b90032ee25db1a6a823e8bb0661b5c..f04cbbe75d6469bd9feb358e920ea9ec842d8e9f 100644 (file)
@@ -288,6 +288,9 @@ static struct caps_opt caps_opt[] = {
 static struct caps_opt caps_opt[] = {};
 #endif
 
+const char *dev_base_path = "/dev/.lxc";
+const char *dev_user_path = "/dev/.lxc/user";
+
 static int run_buffer(char *buffer)
 {
        struct lxc_popen_FILE *f;
@@ -1259,13 +1262,11 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
        struct stat s;
        char tmp_path[MAXPATHLEN];
        char fstype[MAX_FSTYPE_LEN];
-       char *base_path = "/dev/.lxc";
-       char *user_path = "/dev/.lxc/user";
        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 */
-               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 ) {
                        SYSERROR( "Unable to create /dev/.lxc for autodev" );
                        return NULL;
@@ -1299,19 +1300,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.
                 * If this doesn't work, we'll have to fall back in the
                 * 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 ) {
                        /* Issue an error but don't fail yet! */
                        ERROR("Unable to create /dev/.lxc/user");
                }
                /* 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);
        }
 
        /*
@@ -1326,18 +1327,18 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
 
        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)
                return NULL;
 
        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);
                if ( ret ) {
-                       /* Something must have failed with the base_path...
-                        * Maybe unpriv user.  Try user_path now... */
+                       /* Something must have failed with the dev_base_path...
+                        * Maybe unpriv user.  Try dev_user_path now... */
                        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)
                                return NULL;
 
@@ -1355,7 +1356,6 @@ static char *mk_devtmpfs(const char *name, char *path, const char *lxcpath)
        return path;
 }
 
-
 /*
  * Do we want to add options for max size of /dev and a file to
  * specify which devices to create?
@@ -1481,6 +1481,61 @@ static int setup_autodev(const char *root)
        return 0;
 }
 
+/*
+ * 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
  * answer is yes.
index a97aa264c18a9e3dd0481eb4b0711421318e587c..df66f994a219bda0a4d998bf52182ab22e1b9cc2 100644 (file)
@@ -391,6 +391,7 @@ 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_groups(struct lxc_conf *c);
 extern int lxc_clear_environment(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,
                           const char *lxcpath);
index 60f07772f7278f98ff11b160049f81379920da61..6c7ac6ab8f5ac66bef54863e1338cd107e9cde40 100644 (file)
@@ -477,6 +477,7 @@ static void lxc_fini(const char *name, struct lxc_handler *handler)
 
        lxc_console_delete(&handler->conf->console);
        lxc_delete_tty(&handler->conf->tty_info);
+       lxc_delete_autodev(handler);
        close(handler->conf->maincmd_fd);
        handler->conf->maincmd_fd = -1;
        free(handler->name);