2 #define _FILE_OFFSET_BITS 64
10 #include <sys/param.h>
12 #include <sys/statvfs.h>
13 #include <sys/ucred.h>
14 #include <sys/mount.h>
24 #pragma GCC diagnostic ignored "-Wformat" // shut warning on '%z'
63 static const char procfs[] =
"/proc/filesystems";
64 FILE *fs = fopen(procfs,
"r");
68 <<
"Cannot read '" << procfs <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
76 char *fstype =
nullptr;
80 if ((nread = getdelim(&
type, &len,
'\t', fs)) == -1 && !feof(fs)) {
81 fprintf(
stderr,
"%s:%d: %s (%zd; 1)\n", procfs,
line, strerror(errno), nread);
87 if ((nread = getdelim(&fstype, &len,
'\n', fs)) == -1 && !feof(fs)) {
88 fprintf(
stderr,
"%s:%d: %s (%zd; 2)\n", procfs,
line, strerror(errno), nread);
101 if (!strcmp(
type,
"nodev\t") || !strcmp(fstype,
"lustre\n") || !strncmp(fstype,
"fuse", 4)) {
108 fstype[nread - 1] = 0;
130 struct statfs *
m = static_cast<struct statfs *>(
arg);
131 size_t infolen =
sizeof(
struct FSInfo);
132 size_t fslen = strlen(
m->f_mntfromname) + 1;
133 size_t dirlen = strlen(
m->f_mntonname) + 1;
134 size_t typelen = strlen(
m->f_fstypename) + 1;
135 size_t totlen = infolen + fslen + dirlen + typelen;
138 i->fsname = strncpy(
p += infolen,
m->f_mntfromname, fslen);
139 i->type = strncpy(
p += fslen,
m->f_fstypename, typelen);
140 i->dir = strncpy(
p += typelen,
m->f_mntonname, dirlen);
141 i->dev =
m->f_fsid.val[0];
142 i->fstype =
m->f_type;
146 if (
m->f_bsize > 0) {
147 i->freespc =
m->f_bavail;
148 i->freespc *=
m->f_bsize;
149 i->freespc /= 1024. * 1024. * 1024.;
157 i->local = ((
m->f_flags & MNT_LOCAL) ? 1 : 0);
162 mntent *
m = static_cast<mntent *>(
arg);
163 size_t infolen =
sizeof(
struct FSInfo);
164 size_t fslen = strlen(
m->mnt_fsname) + 1;
165 size_t dirlen = strlen(
m->mnt_dir) + 1;
166 size_t typelen = strlen(
m->mnt_type) + 1;
167 size_t originlen = strlen(
m->mnt_fsname) + 1;
168 size_t totlen = infolen + fslen + dirlen + typelen + originlen;
171 i->fsname = static_cast<char *>(memcpy(
p += infolen,
m->mnt_fsname, fslen));
172 i->type = static_cast<char *>(memcpy(
p += fslen,
m->mnt_type, typelen));
173 i->dir = static_cast<char *>(memcpy(
p += typelen,
m->mnt_dir, dirlen));
174 i->origin = static_cast<char *>(memcpy(
p += dirlen,
m->mnt_fsname, originlen));
180 i->bind = strstr(
m->mnt_opts,
"bind") !=
nullptr;
182 for (
size_t j = 0;
j <
fstypes_.size() && !
i->local; ++
j)
199 struct statfs *mtab = 0;
200 if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0) {
203 <<
"getmntinfo() failed: " << strerror(nerr) <<
" (error " << nerr <<
")";
208 for (
int ix = 0; ix < rc; ++ix)
213 const char *
const _PATH_MOUNTED_LINUX =
"/proc/self/mounts";
215 FILE *mtab = setmntent(_PATH_MOUNTED_LINUX,
"r");
219 <<
"Cannot read '" << _PATH_MOUNTED_LINUX <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
224 while ((
m = getmntent(mtab)))
247 if (lstat(
i->dir, &
s) < 0) {
251 if (nerr != ENOENT && nerr != EACCES)
253 <<
"Cannot lstat('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
257 if (statfs(
i->dir, &sfs) < 0) {
261 <<
"Cannot statfs('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
266 i->fstype = sfs.f_type;
267 if (sfs.f_bsize > 0) {
268 i->freespc = sfs.f_bavail;
269 i->freespc *= sfs.f_bsize;
270 i->freespc /= 1024. * 1024. * 1024.;
273 }
else if (
i->fstype == -1) {
297 std::vector<std::string> &prev_paths)
const {
298 for (
const auto &old_path : prev_paths) {
299 if (!strcmp(old_path.c_str(),
path)) {
300 edm::LogWarning(
"LocalFileSystem::findMount()") <<
"Found a loop in bind mounts; stopping evaluation.";
307 size_t len = strlen(
path);
308 for (
size_t i = 0;
i <
fs_.size(); ++
i) {
317 size_t fslen = strlen(
fs_[
i]->
dir);
319 ((fslen == 1 &&
fs_[
i]->
dir[0] ==
'/') || len == fslen ||
path[fslen] ==
'/') &&
320 (!best || fslen > bestlen || (fslen == bestlen && !best->local))) {
330 if (
fs_[
i]->dev !=
s->st_dev ||
fs_[
i]->fstype != sfs->f_type) {
352 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
360 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
365 prev_paths.push_back(
path);
367 return new_best ? new_best : best;
393 <<
"Cannot lstat('" <<
fullpath <<
"' alias '" <<
path <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
401 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
406 std::vector<std::string> prev_paths;
410 return m ?
m->local :
false;
432 double minFreeSpace)
const {
435 std::ostringstream warningst;
436 warningst <<
"Cannot use lazy-download because:\n";
438 for (
size_t i = 0,
e =
paths.size();
i <
e; ++
i) {
440 const char *inpath =
paths[
i].c_str();
441 const char *
path = inpath;
444 char *
p = std::getenv(
path + 1);
447 else if (!strcmp(
path,
"$TMPDIR"))
456 <<
"Checking if '" <<
fullpath <<
"', from '"
457 << inpath <<
"' is valid cache path with "
458 << minFreeSpace <<
" free space" << std::endl;
463 if (nerr != ENOENT && nerr != EACCES)
465 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
473 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
478 std::vector<std::string> prev_paths;
482 <<
"Candidate '" <<
fullpath <<
"': "
483 <<
"found=" << (
m ? 1 : 0)
484 <<
" local=" << (
m &&
m->local)
485 <<
" free=" << (
m ?
m->freespc : 0)
486 <<
" access=" << access(
fullpath, W_OK)
490 if (
m &&
m->local &&
m->freespc >= minFreeSpace && access(
fullpath, W_OK) == 0) {
496 warningst <<
"- The mount " <<
fullpath <<
" is not local.\n";
497 }
else if (
m->freespc < minFreeSpace) {
498 warningst <<
" - The mount at " <<
fullpath <<
" has only " <<
m->freespc <<
" GB free; a minumum of "
499 << minFreeSpace <<
" GB is required.\n";
500 }
else if (access(
fullpath, W_OK)) {
501 warningst <<
" - The process has no permission to write into " <<
fullpath <<
"\n";
509 if (!warning_str.empty()) {
510 warning_str = warning_str.substr(0, warning_str.size() - 2);
527 for (
size_t i = 0,
e =
fs_.size();
i <
e; ++
i)