CMS 3D CMS Logo

LocalFileSystem.cc
Go to the documentation of this file.
1 #define _GNU_SOURCE 1
2 #define _FILE_OFFSET_BITS 64
5 #include <cerrno>
6 #include <cstdio>
7 #include <cstdlib>
8 #include <cstring>
9 #include <cassert>
10 #include <sys/param.h>
11 #if BSD
12 #include <sys/statvfs.h>
13 #include <sys/ucred.h>
14 #include <sys/mount.h>
15 #else
16 #include <mntent.h>
17 #include <sys/vfs.h>
18 #endif
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <iostream>
22 #include <atomic>
23 
24 #pragma GCC diagnostic ignored "-Wformat" // shut warning on '%z'
25 
28  char *fsname; //< file system name
29  char *type; //< file system type
30  char *dir; //< mount point directory
31  char *origin = nullptr; //< mount origin
32  dev_t dev; //< device id
33  long fstype; //< file system id
34  double freespc; //< free space in megabytes
35  unsigned local : 1; //< flag for local device
36  unsigned bind : 1; //< flag for bind mounts
37  std::atomic<bool> checked; //< flag for valid dev, fstype
38 };
39 
60  int ret = 0;
61 
62 #if __linux__
63  static const char procfs[] = "/proc/filesystems";
64  FILE *fs = fopen(procfs, "r");
65  if (!fs) {
66  int nerr = errno;
67  edm::LogWarning("LocalFileSystem::readFSTypes()")
68  << "Cannot read '" << procfs << "': " << strerror(nerr) << " (error " << nerr << ")";
69  return -1;
70  }
71 
72  ssize_t nread;
73  int line = 0;
74  while (!feof(fs)) {
75  char *type = nullptr;
76  char *fstype = nullptr;
77  size_t len = 0;
78  ++line;
79 
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);
82  free(type);
83  ret = -1;
84  break;
85  }
86 
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);
89  free(type);
90  free(fstype);
91  ret = -1;
92  break;
93  }
94 
95  if (feof(fs)) {
96  free(type);
97  free(fstype);
98  break;
99  }
100 
101  if (!strcmp(type, "nodev\t") || !strcmp(fstype, "lustre\n") || !strncmp(fstype, "fuse", 4)) {
102  free(type);
103  free(fstype);
104  continue;
105  }
106 
107  assert(nread >= 1);
108  fstype[nread - 1] = 0;
109  fstypes_.push_back(fstype);
110  free(fstype);
111  free(type);
112  }
113 
114  fclose(fs);
115 #endif // __linux__
116 
117  return ret;
118 }
119 
129 #if BSD
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;
136  FSInfo *i = (FSInfo *)malloc(totlen);
137  char *p = (char *)i;
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;
143  i->freespc = 0;
144  i->bind = 0;
145  i->origin = nullptr;
146  if (m->f_bsize > 0) {
147  i->freespc = m->f_bavail;
148  i->freespc *= m->f_bsize;
149  i->freespc /= 1024. * 1024. * 1024.;
150  }
151  /* FIXME: This incorrectly says that mounted disk images are local,
152  even if it was mounted from a network server. The alternative is
153  to walk up the device tree using either a) process IORegistry to
154  get the device tree, which lists devices for disk images, and from
155  there translate volume uuid to a mount point; b) parse output from
156  'hdiutil info -plist' to determine image-path / dev-entry map. */
157  i->local = ((m->f_flags & MNT_LOCAL) ? 1 : 0);
158  i->checked = 1;
159  return i;
160 
161 #else // ! BSD
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;
169  FSInfo *i = (FSInfo *)malloc(totlen);
170  char *p = (char *)i;
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));
175  i->dev = -1;
176  i->fstype = -1;
177  i->freespc = 0;
178  i->local = 0;
179  i->checked = false;
180  i->bind = strstr(m->mnt_opts, "bind") != nullptr;
181 
182  for (size_t j = 0; j < fstypes_.size() && !i->local; ++j)
183  if (fstypes_[j] == i->type)
184  i->local = 1;
185 #endif // BSD
186 
187  return i;
188 }
189 
197 #if BSD
198  int rc;
199  struct statfs *mtab = 0;
200  if ((rc = getmntinfo(&mtab, MNT_NOWAIT)) < 0) {
201  int nerr = errno;
202  edm::LogWarning("LocalFileSystem::initFSList()")
203  << "getmntinfo() failed: " << strerror(nerr) << " (error " << nerr << ")";
204  return -1;
205  }
206 
207  fs_.reserve(rc);
208  for (int ix = 0; ix < rc; ++ix)
209  fs_.push_back(initFSInfo(&mtab[ix]));
210 
211  free(mtab);
212 #else
213  const char *const _PATH_MOUNTED_LINUX = "/proc/self/mounts";
214  struct mntent *m;
215  FILE *mtab = setmntent(_PATH_MOUNTED_LINUX, "r");
216  if (!mtab) {
217  int nerr = errno;
218  edm::LogWarning("LocalFileSystem::initFSList()")
219  << "Cannot read '" << _PATH_MOUNTED_LINUX << "': " << strerror(nerr) << " (error " << nerr << ")";
220  return -1;
221  }
222 
223  fs_.reserve(20);
224  while ((m = getmntent(mtab)))
225  fs_.push_back(initFSInfo(m));
226 
227  endmntent(mtab);
228 #endif
229 
230  return 0;
231 }
232 
242  int ret = 0;
243  struct stat s;
244  struct statfs sfs;
245 
246  if (!i->checked) {
247  if (lstat(i->dir, &s) < 0) {
248  i->checked = true;
249 
250  int nerr = errno;
251  if (nerr != ENOENT && nerr != EACCES)
252  edm::LogWarning("LocalFileSystem::statFSInfo()")
253  << "Cannot lstat('" << i->dir << "'): " << strerror(nerr) << " (error " << nerr << ")";
254  return -1;
255  }
256 
257  if (statfs(i->dir, &sfs) < 0) {
258  i->checked = true;
259  int nerr = errno;
260  edm::LogWarning("LocalFileSystem::statFSInfo()")
261  << "Cannot statfs('" << i->dir << "'): " << strerror(nerr) << " (error " << nerr << ")";
262  return -1;
263  }
264 
265  i->dev = s.st_dev;
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.;
271  }
272  i->checked = true;
273  } else if (i->fstype == -1) {
274  errno = ENOENT;
275  ret = -1;
276  }
277 
278  return ret;
279 }
280 
295  struct statfs *sfs,
296  struct stat *s,
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.";
301  return nullptr;
302  }
303  }
304 
305  FSInfo *best = nullptr;
306  size_t bestlen = 0;
307  size_t len = strlen(path);
308  for (size_t i = 0; i < fs_.size(); ++i) {
309  // First match simply against the file system path. We don't
310  // touch the file system until the path prefix matches.
311  // When we have a path prefix match, check the file system if
312  // we don't have a best match candidate yet, OR
313  // this match is longer (more specific) than the previous best OR
314  // this match is the same length and the previous best isn't local
315  // The final condition handles cases such as '/' that can appear twice
316  // in the file system list, once as 'rootfs' and once as local fs.
317  size_t fslen = strlen(fs_[i]->dir);
318  if (!strncmp(fs_[i]->dir, path, fslen) &&
319  ((fslen == 1 && fs_[i]->dir[0] == '/') || len == fslen || path[fslen] == '/') &&
320  (!best || fslen > bestlen || (fslen == bestlen && !best->local))) {
321  // Get the file system device and file system ids.
322  if (statFSInfo(fs_[i]) < 0)
323  return nullptr;
324 
325  // Check the path is on the same device / file system. If this
326  // fails, we found a better prefix match on path, but it's the
327  // wrong device, so reset our idea of the best match: it can't
328  // be the outer mount any more. Not sure this is the right
329  // thing to do with e.g. loop-back or union mounts.
330  if (fs_[i]->dev != s->st_dev || fs_[i]->fstype != sfs->f_type) {
331  best = nullptr;
332  continue;
333  }
334 
335  // OK this is better than anything else we found so far.
336  best = fs_[i];
337  bestlen = fslen;
338  }
339  }
340  // In the case of a bind mount, try looking again at the source directory.
341  if (best && best->bind && best->origin) {
342  struct stat s2;
343  struct statfs sfs2;
344  char *fullpath = realpath(best->origin, nullptr);
345 
346  if (!fullpath)
347  fullpath = strdup(best->origin);
348 
349  if (lstat(fullpath, &s2) < 0) {
350  int nerr = errno;
351  edm::LogWarning("LocalFileSystem::findMount()") << "Cannot lstat('" << fullpath << "' alias '" << path
352  << "'): " << strerror(nerr) << " (error " << nerr << ")";
353  free(fullpath);
354  return best;
355  }
356 
357  if (statfs(fullpath, &sfs2) < 0) {
358  int nerr = errno;
359  edm::LogWarning("LocalFileSystem::findMount()") << "Cannot statfs('" << fullpath << "' alias '" << path
360  << "'): " << strerror(nerr) << " (error " << nerr << ")";
361  free(fullpath);
362  return best;
363  }
364 
365  prev_paths.push_back(path);
366  LocalFileSystem::FSInfo *new_best = findMount(fullpath, &sfs2, &s2, prev_paths);
367  return new_best ? new_best : best;
368  }
369 
370  return best;
371 }
372 
383  struct stat s;
384  struct statfs sfs;
385  char *fullpath = realpath(path.c_str(), nullptr);
386 
387  if (!fullpath)
388  fullpath = strdup(path.c_str());
389 
390  if (lstat(fullpath, &s) < 0) {
391  int nerr = errno;
392  edm::LogWarning("LocalFileSystem::isLocalPath()")
393  << "Cannot lstat('" << fullpath << "' alias '" << path << "'): " << strerror(nerr) << " (error " << nerr << ")";
394  free(fullpath);
395  return false;
396  }
397 
398  if (statfs(fullpath, &sfs) < 0) {
399  int nerr = errno;
400  edm::LogWarning("LocalFileSystem::isLocalPath()") << "Cannot statfs('" << fullpath << "' alias '" << path
401  << "'): " << strerror(nerr) << " (error " << nerr << ")";
402  free(fullpath);
403  return false;
404  }
405 
406  std::vector<std::string> prev_paths;
407  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
408  free(fullpath);
409 
410  return m ? m->local : false;
411 }
412 
431 std::pair<std::string, std::string> LocalFileSystem::findCachePath(const std::vector<std::string> &paths,
432  double minFreeSpace) const {
433  struct stat s;
434  struct statfs sfs;
435  std::ostringstream warningst;
436  warningst << "Cannot use lazy-download because:\n";
437 
438  for (size_t i = 0, e = paths.size(); i < e; ++i) {
439  char *fullpath;
440  const char *inpath = paths[i].c_str();
441  const char *path = inpath;
442 
443  if (*path == '$') {
444  char *p = std::getenv(path + 1);
445  if (p && *p)
446  path = p;
447  else if (!strcmp(path, "$TMPDIR"))
448  path = "/tmp";
449  }
450 
451  if (!(fullpath = realpath(path, nullptr)))
452  fullpath = strdup(path);
453 
454 #if 0
455  std::cerr /* edm::LogInfo("LocalFileSystem") */
456  << "Checking if '" << fullpath << "', from '"
457  << inpath << "' is valid cache path with "
458  << minFreeSpace << " free space" << std::endl;
459 #endif
460 
461  if (lstat(fullpath, &s) < 0) {
462  int nerr = errno;
463  if (nerr != ENOENT && nerr != EACCES)
464  edm::LogWarning("LocalFileSystem::findCachePath()") << "Cannot lstat('" << fullpath << "', from '" << inpath
465  << "'): " << strerror(nerr) << " (error " << nerr << ")";
466  free(fullpath);
467  continue;
468  }
469 
470  if (statfs(fullpath, &sfs) < 0) {
471  int nerr = errno;
472  edm::LogWarning("LocalFileSystem::findCachePath()") << "Cannot statfs('" << fullpath << "', from '" << inpath
473  << "'): " << strerror(nerr) << " (error " << nerr << ")";
474  free(fullpath);
475  continue;
476  }
477 
478  std::vector<std::string> prev_paths;
479  FSInfo *m = findMount(fullpath, &sfs, &s, prev_paths);
480 #if 0
481  std::cerr /* edm::LogInfo("LocalFileSystem") */
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)
487  << std::endl;
488 #endif
489 
490  if (m && m->local && m->freespc >= minFreeSpace && access(fullpath, W_OK) == 0) {
492  free(fullpath);
493  return std::make_pair(result, std::string());
494  } else if (m) {
495  if (!m->local) {
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";
502  }
503  }
504 
505  free(fullpath);
506  }
507 
508  std::string warning_str = warningst.str();
509  if (!warning_str.empty()) {
510  warning_str = warning_str.substr(0, warning_str.size() - 2);
511  }
512 
513  return std::make_pair(std::string(), std::move(warning_str));
514 }
515 
518  if (readFSTypes() < 0)
519  return;
520 
521  if (initFSList() < 0)
522  return;
523 }
524 
527  for (size_t i = 0, e = fs_.size(); i < e; ++i)
528  free(fs_[i]);
529 }
runTheMatrix.ret
ret
prodAgent to be discontinued
Definition: runTheMatrix.py:355
LocalFileSystem::FSInfo::fstype
long fstype
Definition: LocalFileSystem.cc:33
LocalFileSystem::FSInfo::fsname
char * fsname
Definition: LocalFileSystem.cc:28
LocalFileSystem::initFSList
int initFSList(void)
Definition: LocalFileSystem.cc:196
LocalFileSystem::findMount
FSInfo * findMount(const char *path, struct statfs *sfs, struct stat *s, std::vector< std::string > &) const
Definition: LocalFileSystem.cc:294
parallelization.stderr
stderr
Definition: parallelization.py:172
LocalFileSystem::FSInfo::origin
char * origin
Definition: LocalFileSystem.cc:31
mps_fire.i
i
Definition: mps_fire.py:355
MessageLogger.h
reco_skim_cfg_mod.fullpath
fullpath
Definition: reco_skim_cfg_mod.py:202
LocalFileSystem::fstypes_
std::vector< std::string > fstypes_
Definition: LocalFileSystem.h:29
AlCaHLTBitMon_ParallelJobs.p
p
Definition: AlCaHLTBitMon_ParallelJobs.py:153
cms::cuda::assert
assert(be >=bs)
LocalFileSystem::fs_
std::vector< FSInfo * > fs_
Definition: LocalFileSystem.h:28
indexGen.s2
s2
Definition: indexGen.py:107
alignCSCRings.s
s
Definition: alignCSCRings.py:92
LocalFileSystem::findCachePath
std::pair< std::string, std::string > findCachePath(const std::vector< std::string > &paths, double minFreeSpace) const
Definition: LocalFileSystem.cc:431
hgcalPlots.stat
stat
Definition: hgcalPlots.py:1111
visualization-live-secondInstance_cfg.m
m
Definition: visualization-live-secondInstance_cfg.py:72
LocalFileSystem::statFSInfo
int statFSInfo(FSInfo *i) const
Definition: LocalFileSystem.cc:241
LocalFileSystem::FSInfo::dev
dev_t dev
Definition: LocalFileSystem.cc:32
AlCaHLTBitMon_QueryRunRegistry.string
string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
edm::LogWarning
Definition: MessageLogger.h:141
LocalFileSystem.h
beam_dqm_sourceclient-live_cfg.cerr
cerr
Definition: beam_dqm_sourceclient-live_cfg.py:17
LocalFileSystem::readFSTypes
int readFSTypes(void)
Definition: LocalFileSystem.cc:59
LocalFileSystem::initFSInfo
FSInfo * initFSInfo(void *p)
Definition: LocalFileSystem.cc:128
LocalFileSystem::~LocalFileSystem
~LocalFileSystem(void)
Definition: LocalFileSystem.cc:526
LocalFileSystem::LocalFileSystem
LocalFileSystem(void)
Definition: LocalFileSystem.cc:517
LocalFileSystem::FSInfo::bind
unsigned bind
Definition: LocalFileSystem.cc:36
LocalFileSystem::FSInfo
Information about file systems on this node.
Definition: LocalFileSystem.cc:27
type
type
Definition: HCALResponse.h:21
eostools.move
def move(src, dest)
Definition: eostools.py:511
Skims_PA_cff.paths
paths
Definition: Skims_PA_cff.py:18
funct::arg
A arg
Definition: Factorize.h:36
mps_fire.result
result
Definition: mps_fire.py:303
castor_dqm_sourceclient_file_cfg.path
path
Definition: castor_dqm_sourceclient_file_cfg.py:37
DTRecHitClients_cfi.local
local
Definition: DTRecHitClients_cfi.py:10
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
LocalFileSystem::isLocalPath
bool isLocalPath(const std::string &path) const
Definition: LocalFileSystem.cc:382
LocalFileSystem::FSInfo::type
char * type
Definition: LocalFileSystem.cc:29
mps_splice.line
line
Definition: mps_splice.py:76
LocalFileSystem::FSInfo::checked
std::atomic< bool > checked
Definition: LocalFileSystem.cc:37
LocalFileSystem::FSInfo::freespc
double freespc
Definition: LocalFileSystem.cc:34
DeadROC_duringRun.dir
dir
Definition: DeadROC_duringRun.py:23
MillePedeFileConverter_cfg.e
e
Definition: MillePedeFileConverter_cfg.py:37
LocalFileSystem::FSInfo::dir
char * dir
Definition: LocalFileSystem.cc:30