]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
Fix `get_min_memlimit()` on non-glibc
authorJack O'Sullivan <jackos1998@gmail.com>
Thu, 3 Sep 2020 21:39:05 +0000 (22:39 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 4 Sep 2020 15:32:17 +0000 (17:32 +0200)
Signed-off-by: Jack O'Sullivan <j@ckos.ie>
[christian.brauner@ubuntu.com: fix coding style]
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/proc_fuse.c

index a99162c31afee5d8bb667575cae295223e517d74..04183e1580c732fa6a234153a68d18d16e82fbb3 100644 (file)
@@ -213,6 +213,68 @@ static uint64_t get_memlimit(const char *cgroup, bool swap)
        return memlimit;
 }
 
+/*
+ * This function taken from glibc-2.32, as POSIX dirname("/some-dir") will
+ * return "/some-dir" as opposed to "/", which breaks `get_min_memlimit()`
+ */
+static char *gnu_dirname(char *path)
+{
+       static const char dot[] = ".";
+       char *last_slash;
+
+       /* Find last '/'.  */
+       last_slash = path != NULL ? strrchr(path, '/') : NULL;
+
+       if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') {
+               /* Determine whether all remaining characters are slashes.  */
+               char *runp;
+
+               for (runp = last_slash; runp != path; --runp)
+                       if (runp[-1] != '/')
+                               break;
+
+               /* The '/' is the last character, we have to look further.  */
+               if (runp != path)
+                       last_slash = memrchr(path, '/', runp - path);
+       }
+
+       if (last_slash != NULL) {
+               /* Determine whether all remaining characters are slashes.  */
+               char *runp;
+
+               for (runp = last_slash; runp != path; --runp)
+                       if (runp[-1] != '/')
+                               break;
+
+               /* Terminate the path.  */
+               if (runp == path) {
+                       /*
+                        * The last slash is the first character in the string.
+                        * We have to return "/".  As a special case we have to
+                        * return "//" if there are exactly two slashes at the
+                        * beginning of the string.  See XBD 4.10 Path Name
+                        * Resolution for more information
+                        */
+                       if (last_slash == path + 1)
+                               ++last_slash;
+                       else
+                               last_slash = path + 1;
+               } else
+                       last_slash = runp;
+
+               last_slash[0] = '\0';
+       } else {
+               /*
+                * This assignment is ill-designed but the XPG specs require to
+                * return a string containing "." in any case no directory part
+                * is found and so a static and constant string is required.
+                */
+               path = (char *)dot;
+       }
+
+       return path;
+}
+
 static uint64_t get_min_memlimit(const char *cgroup, bool swap)
 {
        __do_free char *copy = NULL;
@@ -224,10 +286,14 @@ static uint64_t get_min_memlimit(const char *cgroup, bool swap)
 
        retlimit = get_memlimit(copy, swap);
 
-       while (strcmp(copy, "/") != 0) {
+       /*
+        * If the cgroup doesn't start with / (probably won't happen), dirname()
+        * will terminate with "" instead of "/"
+        */
+       while (*copy && strcmp(copy, "/") != 0) {
                char *it = copy;
 
-               it = dirname(it);
+               it = gnu_dirname(it);
                memlimit = get_memlimit(it, swap);
                if (memlimit > 0 && memlimit < retlimit)
                        retlimit = memlimit;