iproute2/lib/fs.c
Luca Boccassi 6d2fd4a53f Include bsd/string.h only in include/utils.h
This is simpler and cleaner, and avoids having to include the header
from every file where the functions are used. The prototypes of the
internal implementation are in this header, so utils.h will have to be
included anyway for those.

Fixes: 508f3c231e ("Use libbsd for strlcpy if available")

Signed-off-by: Luca Boccassi <bluca@debian.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2018-11-05 08:38:32 -08:00

183 lines
3.3 KiB
C

/*
* 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 <dsa@cumulusnetworks.com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/mount.h>
#include <ctype.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 %4095s %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)
goto out;
if (errno == ENODEV) {
fprintf(stderr,
"Failed to mount cgroup2. Are CGROUPS enabled in your kernel?\n");
} else {
fprintf(stderr,
"Failed to mount cgroup2: %s\n",
strerror(errno));
}
free(mnt);
return NULL;
}
out:
return mnt;
}
int make_path(const char *path, mode_t mode)
{
char *dir, *delim;
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';
rc = mkdir(dir, mode);
if (mkdir(dir, mode) != 0 && errno != EEXIST) {
fprintf(stderr, "mkdir failed for %s: %s\n",
dir, strerror(errno));
goto out;
}
if (delim == NULL)
break;
*delim = '/';
delim++;
if (*delim == '\0')
break;
}
rc = 0;
out:
free(dir);
return rc;
}
int get_command_name(const char *pid, char *comm, size_t len)
{
char path[PATH_MAX];
char line[128];
FILE *fp;
if (snprintf(path, sizeof(path),
"/proc/%s/status", pid) >= sizeof(path)) {
return -1;
}
fp = fopen(path, "r");
if (!fp)
return -1;
comm[0] = '\0';
while (fgets(line, sizeof(line), fp)) {
char *nl, *name;
name = strstr(line, "Name:");
if (!name)
continue;
name += 5;
while (isspace(*name))
name++;
nl = strchr(name, '\n');
if (nl)
*nl = '\0';
strlcpy(comm, name, len);
break;
}
fclose(fp);
return 0;
}