fs.c revision 1dafceb1c9c6a57506fd4cbf57f721efe59afcda
1/* 2 * fs.c filesystem APIs 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: David Ahern <dsa@cumulusnetworks.com> 10 * 11 */ 12 13#include <sys/types.h> 14#include <sys/stat.h> 15#include <sys/socket.h> 16#include <sys/mount.h> 17#include <fcntl.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <unistd.h> 21#include <string.h> 22#include <errno.h> 23#include <limits.h> 24 25#include "utils.h" 26 27#define CGROUP2_FS_NAME "cgroup2" 28 29/* if not already mounted cgroup2 is mounted here for iproute2's use */ 30#define MNT_CGRP2_PATH "/var/run/cgroup2" 31 32/* return mount path of first occurrence of given fstype */ 33static char *find_fs_mount(const char *fs_to_find) 34{ 35 char path[4096]; 36 char fstype[128]; /* max length of any filesystem name */ 37 char *mnt = NULL; 38 FILE *fp; 39 40 fp = fopen("/proc/mounts", "r"); 41 if (!fp) { 42 fprintf(stderr, 43 "Failed to open mounts file: %s\n", strerror(errno)); 44 return NULL; 45 } 46 47 while (fscanf(fp, "%*s %4096s %127s %*s %*d %*d\n", 48 path, fstype) == 2) { 49 if (strcmp(fstype, fs_to_find) == 0) { 50 mnt = strdup(path); 51 break; 52 } 53 } 54 55 fclose(fp); 56 57 return mnt; 58} 59 60/* caller needs to free string returned */ 61char *find_cgroup2_mount(void) 62{ 63 char *mnt = find_fs_mount(CGROUP2_FS_NAME); 64 65 if (mnt) 66 return mnt; 67 68 mnt = strdup(MNT_CGRP2_PATH); 69 if (!mnt) { 70 fprintf(stderr, "Failed to allocate memory for cgroup2 path\n"); 71 return NULL; 72 73 } 74 75 if (make_path(mnt, 0755)) { 76 fprintf(stderr, "Failed to setup vrf cgroup2 directory\n"); 77 free(mnt); 78 return NULL; 79 } 80 81 if (mount("none", mnt, CGROUP2_FS_NAME, 0, NULL)) { 82 /* EBUSY means already mounted */ 83 if (errno != EBUSY) { 84 fprintf(stderr, 85 "Failed to mount cgroup2. Are CGROUPS enabled in your kernel?\n"); 86 free(mnt); 87 return NULL; 88 } 89 } 90 return mnt; 91} 92 93int make_path(const char *path, mode_t mode) 94{ 95 char *dir, *delim; 96 struct stat sbuf; 97 int rc = -1; 98 99 delim = dir = strdup(path); 100 if (dir == NULL) { 101 fprintf(stderr, "strdup failed copying path"); 102 return -1; 103 } 104 105 /* skip '/' -- it had better exist */ 106 if (*delim == '/') 107 delim++; 108 109 while (1) { 110 delim = strchr(delim, '/'); 111 if (delim) 112 *delim = '\0'; 113 114 if (stat(dir, &sbuf) != 0) { 115 if (errno != ENOENT) { 116 fprintf(stderr, 117 "stat failed for %s: %s\n", 118 dir, strerror(errno)); 119 goto out; 120 } 121 122 if (mkdir(dir, mode) != 0) { 123 fprintf(stderr, 124 "mkdir failed for %s: %s", 125 dir, strerror(errno)); 126 goto out; 127 } 128 } 129 130 if (delim == NULL) 131 break; 132 133 *delim = '/'; 134 delim++; 135 if (*delim == '\0') 136 break; 137 } 138 rc = 0; 139out: 140 free(dir); 141 142 return rc; 143} 144