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 <ctype.h> 18#include <fcntl.h> 19#include <stdio.h> 20#include <stdlib.h> 21#include <unistd.h> 22#include <string.h> 23#include <errno.h> 24#include <limits.h> 25 26#include "utils.h" 27 28#define CGROUP2_FS_NAME "cgroup2" 29 30/* if not already mounted cgroup2 is mounted here for iproute2's use */ 31#define MNT_CGRP2_PATH "/var/run/cgroup2" 32 33/* return mount path of first occurrence of given fstype */ 34static char *find_fs_mount(const char *fs_to_find) 35{ 36 char path[4096]; 37 char fstype[128]; /* max length of any filesystem name */ 38 char *mnt = NULL; 39 FILE *fp; 40 41 fp = fopen("/proc/mounts", "r"); 42 if (!fp) { 43 fprintf(stderr, 44 "Failed to open mounts file: %s\n", strerror(errno)); 45 return NULL; 46 } 47 48 while (fscanf(fp, "%*s %4095s %127s %*s %*d %*d\n", 49 path, fstype) == 2) { 50 if (strcmp(fstype, fs_to_find) == 0) { 51 mnt = strdup(path); 52 break; 53 } 54 } 55 56 fclose(fp); 57 58 return mnt; 59} 60 61/* caller needs to free string returned */ 62char *find_cgroup2_mount(void) 63{ 64 char *mnt = find_fs_mount(CGROUP2_FS_NAME); 65 66 if (mnt) 67 return mnt; 68 69 mnt = strdup(MNT_CGRP2_PATH); 70 if (!mnt) { 71 fprintf(stderr, "Failed to allocate memory for cgroup2 path\n"); 72 return NULL; 73 74 } 75 76 if (make_path(mnt, 0755)) { 77 fprintf(stderr, "Failed to setup vrf cgroup2 directory\n"); 78 free(mnt); 79 return NULL; 80 } 81 82 if (mount("none", mnt, CGROUP2_FS_NAME, 0, NULL)) { 83 /* EBUSY means already mounted */ 84 if (errno == EBUSY) 85 goto out; 86 87 if (errno == ENODEV) { 88 fprintf(stderr, 89 "Failed to mount cgroup2. Are CGROUPS enabled in your kernel?\n"); 90 } else { 91 fprintf(stderr, 92 "Failed to mount cgroup2: %s\n", 93 strerror(errno)); 94 } 95 free(mnt); 96 return NULL; 97 } 98out: 99 return mnt; 100} 101 102int make_path(const char *path, mode_t mode) 103{ 104 char *dir, *delim; 105 int rc = -1; 106 107 delim = dir = strdup(path); 108 if (dir == NULL) { 109 fprintf(stderr, "strdup failed copying path"); 110 return -1; 111 } 112 113 /* skip '/' -- it had better exist */ 114 if (*delim == '/') 115 delim++; 116 117 while (1) { 118 delim = strchr(delim, '/'); 119 if (delim) 120 *delim = '\0'; 121 122 rc = mkdir(dir, mode); 123 if (mkdir(dir, mode) != 0 && errno != EEXIST) { 124 fprintf(stderr, "mkdir failed for %s: %s\n", 125 dir, strerror(errno)); 126 goto out; 127 } 128 129 if (delim == NULL) 130 break; 131 132 *delim = '/'; 133 delim++; 134 if (*delim == '\0') 135 break; 136 } 137 rc = 0; 138out: 139 free(dir); 140 141 return rc; 142} 143 144int get_command_name(const char *pid, char *comm, size_t len) 145{ 146 char path[PATH_MAX]; 147 char line[128]; 148 FILE *fp; 149 150 if (snprintf(path, sizeof(path), 151 "/proc/%s/status", pid) >= sizeof(path)) { 152 return -1; 153 } 154 155 fp = fopen(path, "r"); 156 if (!fp) 157 return -1; 158 159 comm[0] = '\0'; 160 while (fgets(line, sizeof(line), fp)) { 161 char *nl, *name; 162 163 name = strstr(line, "Name:"); 164 if (!name) 165 continue; 166 167 name += 5; 168 while (isspace(*name)) 169 name++; 170 171 nl = strchr(name, '\n'); 172 if (nl) 173 *nl = '\0'; 174 175 strlcpy(comm, name, len); 176 break; 177 } 178 179 fclose(fp); 180 181 return 0; 182} 183