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> 64 constexpr
char procfs[] =
"/proc/filesystems";
65 auto close_ = [](FILE *iFile) { fclose(iFile); };
66 std::unique_ptr<FILE, decltype(close_)>
fs(fopen(procfs,
"r"), close_);
70 <<
"Cannot read '" << procfs <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
76 auto free_ = [](
char **iPtr) { free(*iPtr); };
77 while (!feof(
fs.get())) {
79 std::unique_ptr<char *, decltype(free_)> freeType(&
type, free_);
84 if ((nread = getdelim(&
type, &len,
'\t',
fs.get())) == -1 && !feof(
fs.get())) {
86 .format(
"{}:{}: {} ({}; 1)\n", procfs,
line, strerror(errno), nread);
91 char *fstype =
nullptr;
92 std::unique_ptr<char *, decltype(free_)> freeFSType(&fstype, free_);
93 if ((nread = getdelim(&fstype, &len,
'\n',
fs.get())) == -1 && !feof(
fs.get())) {
95 .format(
"{}:{}: {} ({}; 2)\n", procfs,
line, strerror(errno), nread);
100 if (feof(
fs.get())) {
104 if (!strcmp(
type,
"nodev\t") || !strcmp(fstype,
"lustre\n") || !strncmp(fstype,
"fuse", 4)) {
109 fstype[nread - 1] = 0;
127 struct statfs *
m =
static_cast<struct statfs *
>(
arg);
128 size_t infolen =
sizeof(
struct FSInfo);
129 size_t fslen = strlen(
m->f_mntfromname) + 1;
130 size_t dirlen = strlen(
m->f_mntonname) + 1;
131 size_t typelen = strlen(
m->f_fstypename) + 1;
132 size_t totlen = infolen + fslen + dirlen + typelen;
135 i->fsname = strncpy(
p += infolen,
m->f_mntfromname, fslen);
136 i->type = strncpy(
p += fslen,
m->f_fstypename, typelen);
137 i->dir = strncpy(
p += typelen,
m->f_mntonname, dirlen);
138 i->dev =
m->f_fsid.val[0];
139 i->fstype =
m->f_type;
143 if (
m->f_bsize > 0) {
144 i->freespc =
m->f_bavail;
145 i->freespc *=
m->f_bsize;
146 i->freespc /= 1024. * 1024. * 1024.;
154 i->local = ((
m->f_flags & MNT_LOCAL) ? 1 : 0);
159 mntent *
m =
static_cast<mntent *
>(
arg);
160 size_t infolen =
sizeof(
struct FSInfo);
161 size_t fslen = strlen(
m->mnt_fsname) + 1;
162 size_t dirlen = strlen(
m->mnt_dir) + 1;
163 size_t typelen = strlen(
m->mnt_type) + 1;
164 size_t originlen = strlen(
m->mnt_fsname) + 1;
165 size_t totlen = infolen + fslen + dirlen + typelen + originlen;
168 i->fsname =
static_cast<char *
>(memcpy(
p += infolen,
m->mnt_fsname, fslen));
169 i->type =
static_cast<char *
>(memcpy(
p += fslen,
m->mnt_type, typelen));
170 i->dir =
static_cast<char *
>(memcpy(
p += typelen,
m->mnt_dir, dirlen));
171 i->origin =
static_cast<char *
>(memcpy(
p += dirlen,
m->mnt_fsname, originlen));
177 i->bind = strstr(
m->mnt_opts,
"bind") !=
nullptr;
179 for (
size_t j = 0;
j <
fstypes_.size() && !
i->local; ++
j)
196 struct statfs *mtab = 0;
197 if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0) {
200 <<
"getmntinfo() failed: " << strerror(nerr) <<
" (error " << nerr <<
")";
205 for (
int ix = 0; ix < rc; ++ix)
210 const char *
const _PATH_MOUNTED_LINUX =
"/proc/self/mounts";
212 FILE *mtab = setmntent(_PATH_MOUNTED_LINUX,
"r");
216 <<
"Cannot read '" << _PATH_MOUNTED_LINUX <<
"': " << strerror(nerr) <<
" (error " << nerr <<
")";
221 while ((
m = getmntent(mtab)))
244 if (lstat(
i->dir, &
s) < 0) {
248 if (nerr != ENOENT && nerr != EACCES)
250 <<
"Cannot lstat('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
254 if (statfs(
i->dir, &sfs) < 0) {
258 <<
"Cannot statfs('" <<
i->dir <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
263 i->fstype = sfs.f_type;
264 if (sfs.f_bsize > 0) {
265 i->freespc = sfs.f_bavail;
266 i->freespc *= sfs.f_bsize;
267 i->freespc /= 1024. * 1024. * 1024.;
270 }
else if (
i->fstype == -1) {
294 std::vector<std::string> &prev_paths)
const {
295 for (
const auto &old_path : prev_paths) {
296 if (!strcmp(old_path.c_str(),
path)) {
297 edm::LogWarning(
"LocalFileSystem::findMount()") <<
"Found a loop in bind mounts; stopping evaluation.";
304 size_t len = strlen(
path);
305 for (
size_t i = 0;
i <
fs_.size(); ++
i) {
314 size_t fslen = strlen(
fs_[
i]->
dir);
316 ((fslen == 1 &&
fs_[
i]->
dir[0] ==
'/') || len == fslen ||
path[fslen] ==
'/') &&
317 (!best || fslen > bestlen || (fslen == bestlen && !best->local))) {
327 if (
fs_[
i]->dev !=
s->st_dev ||
fs_[
i]->fstype != sfs->f_type) {
338 if (best && best->bind && best->origin) {
341 char *
fullpath = realpath(best->origin,
nullptr);
349 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
357 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
362 prev_paths.push_back(
path);
364 return new_best ? new_best : best;
390 <<
"Cannot lstat('" <<
fullpath <<
"' alias '" <<
path <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
398 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
403 std::vector<std::string> prev_paths;
407 return m ?
m->local :
false;
429 double minFreeSpace)
const {
432 std::ostringstream warningst;
433 warningst <<
"Cannot use lazy-download because:\n";
435 for (
size_t i = 0,
e =
paths.size();
i <
e; ++
i) {
437 const char *inpath =
paths[
i].c_str();
438 const char *
path = inpath;
441 char *
p = std::getenv(
path + 1);
444 else if (!strcmp(
path,
"$TMPDIR"))
453 <<
"Checking if '" <<
fullpath <<
"', from '" 454 << inpath <<
"' is valid cache path with " 455 << minFreeSpace <<
" free space" << std::endl;
460 if (nerr != ENOENT && nerr != EACCES)
462 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
470 <<
"'): " << strerror(nerr) <<
" (error " << nerr <<
")";
475 std::vector<std::string> prev_paths;
479 <<
"Candidate '" <<
fullpath <<
"': " 480 <<
"found=" << (
m ? 1 : 0)
481 <<
" local=" << (
m &&
m->local)
482 <<
" free=" << (
m ?
m->freespc : 0)
483 <<
" access=" << access(
fullpath, W_OK)
487 if (
m &&
m->local &&
m->freespc >= minFreeSpace && access(
fullpath, W_OK) == 0) {
493 warningst <<
"- The mount " <<
fullpath <<
" is not local.\n";
494 }
else if (
m->freespc < minFreeSpace) {
495 warningst <<
" - The mount at " <<
fullpath <<
" has only " <<
m->freespc <<
" GB free; a minumum of " 496 << minFreeSpace <<
" GB is required.\n";
497 }
else if (access(
fullpath, W_OK)) {
498 warningst <<
" - The process has no permission to write into " <<
fullpath <<
"\n";
506 if (!warning_str.empty()) {
507 warning_str = warning_str.substr(0, warning_str.size() - 2);
524 for (
size_t i = 0,
e =
fs_.size();
i <
e; ++
i)
bool isLocalPath(const std::string &path) const
std::vector< FSInfo * > fs_
std::atomic< bool > checked
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &) const
ret
prodAgent to be discontinued
std::vector< std::string > fstypes_
Information about file systems on this node.
Log< level::Error, false > LogError
int statFSInfo(FSInfo *i) const
FSInfo * initFSInfo(void *p)
Log< level::Warning, false > LogWarning
std::pair< std::string, std::string > findCachePath(const std::vector< std::string > &paths, double minFreeSpace) const