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>
62 constexpr
char procfs[] =
"/proc/filesystems";
63 auto close_ = [](FILE *iFile) { fclose(iFile); };
68 <<
"Cannot read '" << procfs <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
74 auto free_ = [](
char **iPtr) { free(*iPtr); };
75 while (!feof(fs.get())) {
82 if ((nread = getdelim(&
type, &len,
'\t', fs.get())) == -1 && !feof(fs.get())) {
84 .format(
"{}:{}: {} ({}; 1)\n", procfs,
line, strerror(errno), nread);
89 char *fstype =
nullptr;
91 if ((nread = getdelim(&fstype, &len,
'\n', fs.get())) == -1 && !feof(fs.get())) {
93 .format(
"{}:{}: {} ({}; 2)\n", procfs,
line, strerror(errno), nread);
102 if (!strcmp(
type,
"nodev\t") || !strcmp(fstype,
"lustre\n") || !strncmp(fstype,
"fuse", 4)) {
107 fstype[nread - 1] = 0;
125 struct statfs *
m = static_cast<struct statfs *>(
arg);
126 size_t infolen =
sizeof(
struct FSInfo);
127 size_t fslen = strlen(
m->f_mntfromname) + 1;
128 size_t dirlen = strlen(
m->f_mntonname) + 1;
129 size_t typelen = strlen(
m->f_fstypename) + 1;
130 size_t totlen = infolen + fslen + dirlen + typelen;
133 i->fsname = strncpy(
p += infolen,
m->f_mntfromname, fslen);
134 i->type = strncpy(
p += fslen,
m->f_fstypename, typelen);
135 i->dir = strncpy(
p += typelen,
m->f_mntonname, dirlen);
136 i->dev =
m->f_fsid.val[0];
137 i->fstype =
m->f_type;
141 if (
m->f_bsize > 0) {
142 i->freespc =
m->f_bavail;
143 i->freespc *=
m->f_bsize;
144 i->freespc /= 1024. * 1024. * 1024.;
152 i->local = ((
m->f_flags & MNT_LOCAL) ? 1 : 0);
157 mntent *
m = static_cast<mntent *>(
arg);
158 size_t infolen =
sizeof(
struct FSInfo);
159 size_t fslen = strlen(
m->mnt_fsname) + 1;
160 size_t dirlen = strlen(
m->mnt_dir) + 1;
161 size_t typelen = strlen(
m->mnt_type) + 1;
162 size_t originlen = strlen(
m->mnt_fsname) + 1;
163 size_t totlen = infolen + fslen + dirlen + typelen + originlen;
166 i->fsname = static_cast<char *>(memcpy(
p += infolen,
m->mnt_fsname, fslen));
167 i->type = static_cast<char *>(memcpy(
p += fslen,
m->mnt_type, typelen));
168 i->dir = static_cast<char *>(memcpy(
p += typelen,
m->mnt_dir, dirlen));
169 i->origin = static_cast<char *>(memcpy(
p += dirlen,
m->mnt_fsname, originlen));
175 i->bind = strstr(
m->mnt_opts,
"bind") !=
nullptr;
177 for (
size_t j = 0;
j <
fstypes_.size() && !
i->local; ++
j)
194 struct statfs *mtab = 0;
195 if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0) {
198 <<
"getmntinfo() failed: " << strerror(nerr) <<
" (error " << nerr <<
")";
203 for (
int ix = 0; ix < rc; ++ix)
208 const char *
const _PATH_MOUNTED_LINUX =
"/proc/self/mounts";
210 FILE *mtab = setmntent(_PATH_MOUNTED_LINUX,
"r");
214 <<
"Cannot read '" << _PATH_MOUNTED_LINUX <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
219 while ((
m = getmntent(mtab)))
242 if (lstat(
i->dir, &
s) < 0) {
246 if (nerr != ENOENT && nerr != EACCES)
248 <<
"Cannot lstat('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
252 if (statfs(
i->dir, &sfs) < 0) {
256 <<
"Cannot statfs('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
261 i->fstype = sfs.f_type;
262 if (sfs.f_bsize > 0) {
263 i->freespc = sfs.f_bavail;
264 i->freespc *= sfs.f_bsize;
265 i->freespc /= 1024. * 1024. * 1024.;
268 }
else if (
i->fstype == -1) {
292 std::vector<std::string> &prev_paths)
const {
293 for (
const auto &old_path : prev_paths) {
294 if (!strcmp(old_path.c_str(),
path)) {
295 edm::LogWarning(
"LocalFileSystem::findMount()") <<
"Found a loop in bind mounts; stopping evaluation.";
302 size_t len = strlen(
path);
303 for (
size_t i = 0;
i <
fs_.size(); ++
i) {
312 size_t fslen = strlen(
fs_[
i]->
dir);
314 ((fslen == 1 &&
fs_[
i]->
dir[0] ==
'/') || len == fslen ||
path[fslen] ==
'/') &&
315 (!best || fslen > bestlen || (fslen == bestlen && !best->local))) {
325 if (
fs_[
i]->dev !=
s->st_dev ||
fs_[
i]->fstype != sfs->f_type) {
347 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
355 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
360 prev_paths.push_back(
path);
362 return new_best ? new_best : best;
388 <<
"Cannot lstat('" <<
fullpath <<
"' alias '" <<
path <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
396 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
401 std::vector<std::string> prev_paths;
405 return m ?
m->local :
false;
427 double minFreeSpace)
const {
430 std::ostringstream warningst;
431 warningst <<
"Cannot use lazy-download because:\n";
433 for (
size_t i = 0,
e =
paths.size();
i <
e; ++
i) {
435 const char *inpath =
paths[
i].c_str();
436 const char *
path = inpath;
439 char *
p = std::getenv(
path + 1);
442 else if (!strcmp(
path,
"$TMPDIR"))
451 <<
"Checking if '" <<
fullpath <<
"', from '"
452 << inpath <<
"' is valid cache path with "
453 << minFreeSpace <<
" free space" << std::endl;
458 if (nerr != ENOENT && nerr != EACCES)
460 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
468 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
473 std::vector<std::string> prev_paths;
477 <<
"Candidate '" <<
fullpath <<
"': "
478 <<
"found=" << (
m ? 1 : 0)
479 <<
" local=" << (
m &&
m->local)
480 <<
" free=" << (
m ?
m->freespc : 0)
481 <<
" access=" << access(
fullpath, W_OK)
485 if (
m &&
m->local &&
m->freespc >= minFreeSpace && access(
fullpath, W_OK) == 0) {
491 warningst <<
"- The mount " <<
fullpath <<
" is not local.\n";
492 }
else if (
m->freespc < minFreeSpace) {
493 warningst <<
" - The mount at " <<
fullpath <<
" has only " <<
m->freespc <<
" GB free; a minumum of "
494 << minFreeSpace <<
" GB is required.\n";
495 }
else if (access(
fullpath, W_OK)) {
496 warningst <<
" - The process has no permission to write into " <<
fullpath <<
"\n";
504 if (!warning_str.empty()) {
505 warning_str = warning_str.substr(0, warning_str.size() - 2);
522 for (
size_t i = 0,
e =
fs_.size();
i <
e; ++
i)