Add make_path to recursively call mkdir as needed to create a given
path with the given mode.

Add find_cgroup2_mount to lookup path where cgroup2 is mounted. If it
is not already mounted, cgroup2 is mounted under /var/run/cgroup2 for
use by iproute2.

Signed-off-by: David Ahern <d...@cumulusnetworks.com>
---
 include/utils.h |   2 +
 lib/Makefile    |   2 +-
 lib/fs.c        | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 lib/fs.c

diff --git a/include/utils.h b/include/utils.h
index ac4517a3bde1..dc1d6b9607dd 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -257,5 +257,7 @@ int get_guid(__u64 *guid, const char *arg);
 int get_real_family(int rtm_type, int rtm_family);
 
 int cmd_exec(const char *cmd, char **argv, bool do_fork);
+int make_path(const char *path, mode_t mode);
+char *find_cgroup2_mount(void);
 
 #endif /* __UTILS_H__ */
diff --git a/lib/Makefile b/lib/Makefile
index 749073261c49..0c57662b4f8f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@ CFLAGS += -fPIC
 
 UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
        inet_proto.o namespace.o json_writer.o \
-       names.o color.o bpf.o exec.o
+       names.o color.o bpf.o exec.o fs.o
 
 NLOBJ=libgenl.o ll_map.o libnetlink.o
 
diff --git a/lib/fs.c b/lib/fs.c
new file mode 100644
index 000000000000..39cc96dccca9
--- /dev/null
+++ b/lib/fs.c
@@ -0,0 +1,143 @@
+/*
+ * fs.c         filesystem APIs
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Authors:    David Ahern <d...@cumulusnetworks.com>
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "utils.h"
+
+#define CGROUP2_FS_NAME "cgroup2"
+
+/* if not already mounted cgroup2 is mounted here for iproute2's use */
+#define MNT_CGRP2_PATH  "/var/run/cgroup2"
+
+/* return mount path of first occurrence of given fstype */
+static char *find_fs_mount(const char *fs_to_find)
+{
+       char path[4096];
+       char fstype[128];    /* max length of any filesystem name */
+       char *mnt = NULL;
+       FILE *fp;
+
+       fp = fopen("/proc/mounts", "r");
+       if (!fp) {
+               fprintf(stderr,
+                       "Failed to open mounts file: %s\n", strerror(errno));
+               return NULL;
+       }
+
+       while (fscanf(fp, "%*s %4096s %127s %*s %*d %*d\n",
+                     path, fstype) == 2) {
+               if (strcmp(fstype, fs_to_find) == 0) {
+                       mnt = strdup(path);
+                       break;
+               }
+       }
+
+       fclose(fp);
+
+       return mnt;
+}
+
+/* caller needs to free string returned */
+char *find_cgroup2_mount(void)
+{
+       char *mnt = find_fs_mount(CGROUP2_FS_NAME);
+
+       if (mnt)
+               return mnt;
+
+       mnt = strdup(MNT_CGRP2_PATH);
+       if (!mnt) {
+               fprintf(stderr, "Failed to allocate memory for cgroup2 path\n");
+               return NULL;
+
+       }
+
+       if (make_path(mnt, 0755)) {
+               fprintf(stderr, "Failed to setup vrf cgroup2 directory\n");
+               free(mnt);
+               return NULL;
+       }
+
+       if (mount("none", mnt, CGROUP2_FS_NAME, 0, NULL)) {
+               /* EBUSY means already mounted */
+               if (errno != EBUSY) {
+                       fprintf(stderr,
+                               "Failed to mount cgroup2. Are CGROUPS enabled 
in your kernel?\n");
+                       free(mnt);
+                       return NULL;
+               }
+       }
+       return mnt;
+}
+
+int make_path(const char *path, mode_t mode)
+{
+       char *dir, *delim;
+       struct stat sbuf;
+       int rc = -1;
+
+       delim = dir = strdup(path);
+       if (dir == NULL) {
+               fprintf(stderr, "strdup failed copying path");
+               return -1;
+       }
+
+       /* skip '/' -- it had better exist */
+       if (*delim == '/')
+               delim++;
+
+       while (1) {
+               delim = strchr(delim, '/');
+               if (delim)
+                       *delim = '\0';
+
+               if (stat(dir, &sbuf) != 0) {
+                       if (errno != ENOENT) {
+                               fprintf(stderr,
+                                       "stat failed for %s: %s\n",
+                                       dir, strerror(errno));
+                               goto out;
+                       }
+
+                       if (mkdir(dir, mode) != 0) {
+                               fprintf(stderr,
+                                       "mkdir failed for %s: %s",
+                                       dir, strerror(errno));
+                               goto out;
+                       }
+               }
+
+               if (delim == NULL)
+                       break;
+
+               *delim = '/';
+               delim++;
+               if (*delim == '\0')
+                       break;
+       }
+       rc = 0;
+out:
+       free(dir);
+
+       return rc;
+}
-- 
2.1.4

Reply via email to