+static int mount_binds(const char *dest, char **l, unsigned long flags) {
+ char **x, **y;
+
+ STRV_FOREACH_PAIR(x, y, l) {
+ char *where;
+ struct stat source_st, dest_st;
+ int r;
+
+ if (stat(*x, &source_st) < 0) {
+ log_error("failed to stat %s: %m", *x);
+ return -errno;
+ }
+
+ where = strappenda(dest, *y);
+ r = stat(where, &dest_st);
+ if (r == 0) {
+ if ((source_st.st_mode & S_IFMT) != (dest_st.st_mode & S_IFMT)) {
+ log_error("The file types of %s and %s do not match. Refusing bind mount",
+ *x, where);
+ return -EINVAL;
+ }
+ } else if (errno == ENOENT) {
+ r = mkdir_parents_label(where, 0755);
+ if (r < 0) {
+ log_error("Failed to bind mount %s: %s", *x, strerror(-r));
+ return r;
+ }
+ } else {
+ log_error("Failed to bind mount %s: %s", *x, strerror(errno));
+ return -errno;
+ }
+ /* Create the mount point, but be conservative -- refuse to create block
+ * and char devices. */
+ if (S_ISDIR(source_st.st_mode))
+ mkdir_label(where, 0755);
+ else if (S_ISFIFO(source_st.st_mode))
+ mkfifo(where, 0644);
+ else if (S_ISSOCK(source_st.st_mode))
+ mknod(where, 0644 | S_IFSOCK, 0);
+ else if (S_ISREG(source_st.st_mode))
+ touch(where);
+ else {
+ log_error("Refusing to create mountpoint for file: %s", *x);
+ return -ENOTSUP;
+ }
+
+ if (mount(*x, where, "bind", MS_BIND, NULL) < 0) {
+ log_error("mount(%s) failed: %m", where);
+ return -errno;
+ }
+
+ if (flags && mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|flags, NULL) < 0) {
+ log_error("mount(%s) failed: %m", where);
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+