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'
66 static const char procfs[] =
"/proc/filesystems";
67 FILE *fs = fopen(procfs,
"r");
72 <<
"Cannot read '" << procfs <<
"': "
73 << strerror(nerr) <<
" (error " << nerr <<
")";
86 if ((nread = getdelim(&type, &len,
'\t', fs)) == -1 && ! feof(fs))
88 fprintf(stderr,
"%s:%d: %s (%zd; 1)\n",
89 procfs, line, strerror(errno), nread);
95 if ((nread = getdelim(&fstype, &len,
'\n', fs)) == -1 && ! feof(fs))
97 fprintf(stderr,
"%s:%d: %s (%zd; 2)\n",
98 procfs, line, strerror(errno), nread);
112 if (! strcmp(type,
"nodev\t")
113 || ! strcmp(fstype,
"lustre\n")
114 || ! strncmp(fstype,
"fuse", 4))
146 struct statfs *
m =
static_cast<struct statfs *
>(
arg);
147 size_t infolen =
sizeof(
struct FSInfo);
148 size_t fslen = strlen(m->f_mntfromname) + 1;
149 size_t dirlen = strlen(m->f_mntonname) + 1;
150 size_t typelen = strlen(m->f_fstypename) + 1;
151 size_t totlen = infolen + fslen + dirlen + typelen;
153 char *
p = (
char *) i;
154 i->
fsname = strncpy(p += infolen, m->f_mntfromname, fslen);
155 i->
type = strncpy(p += fslen, m->f_fstypename, typelen);
156 i->
dir = strncpy(p += typelen, m->f_mntonname, dirlen);
157 i->
dev = m->f_fsid.val[0];
166 i->
freespc /= 1024. * 1024. * 1024.;
174 i->
local = ((m->f_flags & MNT_LOCAL) ? 1 : 0);
179 mntent *m =
static_cast<mntent *
>(
arg);
180 size_t infolen =
sizeof(
struct FSInfo);
181 size_t fslen = strlen(m->mnt_fsname) + 1;
182 size_t dirlen = strlen(m->mnt_dir) + 1;
183 size_t typelen = strlen(m->mnt_type) + 1;
184 size_t originlen = strlen(m->mnt_fsname) + 1;
185 size_t totlen = infolen + fslen + dirlen + typelen + originlen;
187 char *p = (
char *) i;
188 i->
fsname = strncpy(p += infolen, m->mnt_fsname, fslen);
189 i->
type = strncpy(p += fslen, m->mnt_type, typelen);
190 i->
dir = strncpy(p += typelen, m->mnt_dir, dirlen);
191 i->
origin = strncpy(p += dirlen, m->mnt_fsname, originlen);
197 i->
bind = strstr(m->mnt_opts,
"bind") !=
nullptr;
218 struct statfs *mtab = 0;
219 if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0)
223 <<
"getmntinfo() failed: " << strerror(nerr)
224 <<
" (error " << nerr <<
")";
229 for (
int ix = 0; ix < rc; ++ix)
234 const char *
const _PATH_MOUNTED_LINUX =
"/proc/self/mounts";
236 FILE *mtab = setmntent(_PATH_MOUNTED_LINUX,
"r");
241 <<
"Cannot read '" << _PATH_MOUNTED_LINUX <<
"': "
242 << strerror(nerr) <<
" (error " << nerr <<
")";
247 while ((m = getmntent(mtab)))
273 if (lstat(i->
dir, &s) < 0)
278 if (nerr != ENOENT && nerr != EACCES)
280 <<
"Cannot lstat('" << i->
dir <<
"'): "
281 << strerror(nerr) <<
" (error " << nerr <<
")";
285 if (statfs(i->
dir, &sfs) < 0)
290 <<
"Cannot statfs('" << i->
dir <<
"'): "
291 << strerror(nerr) <<
" (error " << nerr <<
")";
301 i->
freespc /= 1024. * 1024. * 1024.;
330 for (
const auto & old_path : prev_paths)
332 if (!strcmp(old_path.c_str(),
path))
335 <<
"Found a loop in bind mounts; stopping evaluation.";
342 size_t len = strlen(path);
343 for (
size_t i = 0;
i <
fs_.size(); ++
i)
347 size_t fslen = strlen(
fs_[
i]->
dir);
348 if (! strncmp(
fs_[
i]->
dir, path, fslen)
349 && ((fslen == 1 &&
fs_[
i]->
dir[0] ==
'/')
350 || len == fslen || path[fslen] ==
'/')
351 && (! best || fslen > bestlen))
362 if (
fs_[i]->dev != s->st_dev ||
fs_[i]->fstype != sfs->f_type)
378 char *fullpath = realpath(best->
origin, 0);
381 fullpath = strdup(best->
origin);
383 if (lstat(fullpath, &s2) < 0)
387 <<
"Cannot lstat('" << fullpath <<
"' alias '"
388 << path <<
"'): " << strerror(nerr) <<
" (error "
394 if (statfs(fullpath, &sfs2) < 0)
398 <<
"Cannot statfs('" << fullpath <<
"' alias '"
399 << path <<
"'): " << strerror(nerr) <<
" (error "
405 prev_paths.push_back(path);
407 return new_best ? new_best : best;
427 char *fullpath = realpath(path.c_str(), 0);
430 fullpath = strdup(path.c_str());
432 if (lstat(fullpath, &s) < 0)
436 <<
"Cannot lstat('" << fullpath <<
"' alias '"
437 << path <<
"'): " << strerror(nerr) <<
" (error "
443 if (statfs(fullpath, &sfs) < 0)
447 <<
"Cannot statfs('" << fullpath <<
"' alias '"
448 << path <<
"'): " << strerror(nerr) <<
" (error "
454 std::vector<std::string> prev_paths;
458 return m ? m->
local :
false;
479 std::pair<std::string, std::string>
481 double minFreeSpace)
const
485 std::ostringstream warningst;
486 warningst <<
"Cannot use lazy-download because:\n";
488 for (
size_t i = 0,
e = paths.size();
i <
e; ++
i)
491 const char *inpath = paths[
i].c_str();
492 const char *
path = inpath;
496 char *
p = getenv(path+1);
499 else if (! strcmp(path,
"$TMPDIR"))
503 if (! (fullpath = realpath(path, 0)))
504 fullpath = strdup(path);
508 <<
"Checking if '" << fullpath <<
"', from '"
509 << inpath <<
"' is valid cache path with "
510 << minFreeSpace <<
" free space" << std::endl;
513 if (lstat(fullpath, &s) < 0)
516 if (nerr != ENOENT && nerr != EACCES)
518 <<
"Cannot lstat('" << fullpath <<
"', from '"
519 << inpath <<
"'): " << strerror(nerr) <<
" (error "
525 if (statfs(fullpath, &sfs) < 0)
529 <<
"Cannot statfs('" << fullpath <<
"', from '"
530 << inpath <<
"'): " << strerror(nerr) <<
" (error "
536 std::vector<std::string> prev_paths;
540 <<
"Candidate '" << fullpath <<
"': "
541 <<
"found=" << (m ? 1 : 0)
542 <<
" local=" << (m && m->
local)
543 <<
" free=" << (m ? m->
freespc : 0)
544 <<
" access=" << access(fullpath, W_OK)
551 && access(fullpath, W_OK) == 0)
561 warningst <<
"- The mount " << fullpath <<
" is not local.\n";
563 else if (m->
freespc < minFreeSpace)
565 warningst <<
" - The mount at " << fullpath <<
" has only " << m->
freespc <<
" GB free; a minumum of " << minFreeSpace <<
" GB is required.\n";
567 else if (access(fullpath, W_OK))
569 warningst <<
" - The process has no permission to write into " << fullpath <<
"\n";
577 if (warning_str.size())
579 warning_str = warning_str.substr(0, warning_str.size()-2);
582 return std::make_pair(
std::string(), std::move(warning_str));
598 for (
size_t i = 0,
e =
fs_.size();
i <
e; ++
i)
int statFSInfo(FSInfo *i) const
Information about file systems on this node.
std::vector< std::string > fstypes_
FSInfo * initFSInfo(void *p)
bool isLocalPath(const std::string &path) const
std::atomic< bool > checked
std::pair< std::string, std::string > findCachePath(const std::vector< std::string > &paths, double minFreeSpace) const
std::vector< FSInfo * > fs_
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &) const