1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2007 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * Copyright (c) 2009-2014 Cisco Systems, Inc.  All rights reserved.
13  * Copyright (c) 2010      IBM Corporation.  All rights reserved.
14  * Copyright (c) 2012-2013 Los Alamos National Security, LLC.
15  *                         All rights reserved.
16  * Copyright (c) 2014-2020 Intel, Inc.  All rights reserved.
17  * Copyright (c) 2016      University of Houston. All rights reserved.
18  * Copyright (c) 2018      Research Organization for Information Science
19  *                         and Technology (RIST). All rights reserved.
20  * $COPYRIGHT$
21  *
22  * Additional copyrights may follow
23  *
24  * $HEADER$
25  */
26 
27 #include "src/include/pmix_config.h"
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #ifdef HAVE_SHLWAPI_H
36 #include <shlwapi.h>
37 #endif
38 #ifdef HAVE_SYS_PARAM_H
39 #include <sys/param.h>
40 #endif
41 #ifdef HAVE_SYS_MOUNT_H
42 #include <sys/mount.h>
43 #endif
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 #ifdef HAVE_SYS_STAT_H
48 #include <sys/stat.h>
49 #endif
50 #ifdef HAVE_SYS_VFS_H
51 #include <sys/vfs.h>
52 #endif
53 #ifdef HAVE_SYS_STATFS_H
54 #include <sys/statfs.h>
55 #endif
56 #ifdef HAVE_SYS_STATVFS_H
57 #include <sys/statvfs.h>
58 #endif
59 #ifdef HAVE_MNTENT_H
60 #include <mntent.h>
61 #endif
62 #ifdef HAVE_PATHS_H
63 #include <paths.h>
64 #endif
65 
66 #ifdef _PATH_MOUNTED
67 #define MOUNTED_FILE _PATH_MOUNTED
68 #else
69 #define MOUNTED_FILE "/etc/mtab"
70 #endif
71 
72 
73 #include "src/include/pmix_stdint.h"
74 #include "src/util/output.h"
75 #include "src/util/path.h"
76 #include "src/util/os_path.h"
77 #include "src/util/argv.h"
78 
79 /*
80  * Sanity check to ensure we have either statfs or statvfs
81  */
82 #if !defined(HAVE_STATFS) && !defined(HAVE_STATVFS)
83 #error Must have either statfs() or statvfs()
84 #endif
85 
86 /*
87  * Note that some OS's (e.g., NetBSD and Solaris) have statfs(), but
88  * no struct statfs (!).  So check to make sure we have struct statfs
89  * before allowing the use of statfs().
90  */
91 #if defined(HAVE_STATFS) && \
92     (defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || \
93      defined(HAVE_STRUCT_STATFS_F_TYPE))
94 #define USE_STATFS 1
95 #endif
96 
97 static void path_env_load(char *path, int *pargc, char ***pargv);
98 static char *list_env_get(char *var, char **list);
99 
pmix_path_is_absolute(const char * path)100 bool pmix_path_is_absolute( const char *path )
101 {
102     if( PMIX_PATH_SEP[0] == *path ) {
103         return true;
104     }
105     return false;
106 }
107 
108 /**
109  *  Locates a file with certain permissions
110  */
pmix_path_find(char * fname,char ** pathv,int mode,char ** envv)111 char *pmix_path_find(char *fname, char **pathv, int mode, char **envv)
112 {
113     char *fullpath;
114     char *delimit;
115     char *env;
116     char *pfix;
117     int i;
118 
119     /* If absolute path is given, return it without searching. */
120     if( pmix_path_is_absolute(fname) ) {
121         return pmix_path_access(fname, NULL, mode);
122     }
123 
124     /* Initialize. */
125 
126     fullpath = NULL;
127     i = 0;
128 
129     /* Consider each directory until the file is found.  Thus, the
130        order of directories is important. */
131 
132     while (pathv[i] && NULL == fullpath) {
133 
134         /* Replace environment variable at the head of the string. */
135         if ('$' == *pathv[i]) {
136             delimit = strchr(pathv[i], PMIX_PATH_SEP[0]);
137             if (delimit) {
138                 *delimit = '\0';
139             }
140             env = list_env_get(pathv[i]+1, envv);
141             if (delimit) {
142                 *delimit = PMIX_PATH_SEP[0];
143             }
144             if (NULL != env) {
145                 if (!delimit) {
146                     fullpath = pmix_path_access(fname, env, mode);
147                 } else {
148                     pfix = (char*) malloc(strlen(env) + strlen(delimit) + 1);
149                     if (NULL == pfix) {
150                         return NULL;
151                     }
152                     strcpy(pfix, env);
153                     strcat(pfix, delimit);
154                     fullpath = pmix_path_access(fname, pfix, mode);
155                     free(pfix);
156                 }
157             }
158         }
159         else {
160             fullpath = pmix_path_access(fname, pathv[i], mode);
161         }
162         i++;
163     }
164     return pmix_make_filename_os_friendly(fullpath);
165 }
166 
167 /*
168  * Locates a file with certain permissions from a list of search paths
169  */
pmix_path_findv(char * fname,int mode,char ** envv,char * wrkdir)170 char *pmix_path_findv(char *fname, int mode, char **envv, char *wrkdir)
171 {
172     char **dirv;
173     char *fullpath;
174     char *path;
175     int dirc;
176     int i;
177     bool found_dot = false;
178 
179     /* Set the local search paths. */
180 
181     dirc = 0;
182     dirv = NULL;
183 
184     if (NULL != (path = list_env_get("PATH", envv))) {
185         path_env_load(path, &dirc, &dirv);
186     }
187 
188     /* Replace the "." path by the working directory. */
189 
190     if (NULL != wrkdir) {
191         for (i = 0; i < dirc; ++i) {
192             if (0 == strcmp(dirv[i], ".")) {
193                 found_dot = true;
194                 free(dirv[i]);
195                 dirv[i] = strdup(wrkdir);
196                 if (NULL == dirv[i]){
197                     return NULL;
198                 }
199             }
200         }
201     }
202 
203     /* If we didn't find "." in the path and we have a wrkdir, append
204        the wrkdir to the end of the path */
205 
206     if (!found_dot && NULL != wrkdir) {
207         pmix_argv_append(&dirc, &dirv, wrkdir);
208     }
209 
210     if(NULL == dirv)
211         return NULL;
212     fullpath = pmix_path_find(fname, dirv, mode, envv);
213     pmix_argv_free(dirv);
214     return fullpath;
215 }
216 
217 
218 /**
219  *  Forms a complete pathname and checks it for existance and
220  *  permissions
221  *
222  *  Accepts:
223  *      -fname File name
224  *      -path  Path prefix
225  *      -mode  Target permissions which must be satisfied
226  *
227  *  Returns:
228  *      -Full pathname of located file Success
229  *      -NULL Failure
230  */
pmix_path_access(char * fname,char * path,int mode)231 char *pmix_path_access(char *fname, char *path, int mode)
232 {
233     char *fullpath = NULL;
234     struct stat buf;
235 
236     /* Allocate space for the full pathname. */
237     if (NULL == path) {
238         fullpath = pmix_os_path(false, fname, NULL);
239     } else {
240         fullpath = pmix_os_path(false, path, fname, NULL);
241     }
242     if (NULL == fullpath)
243         return NULL;
244 
245     /* first check to see - is this a file or a directory? We
246      * only want files
247      */
248     /* coverity[toctou] */
249     if (0 != stat(fullpath, &buf)) {
250         /* couldn't stat the path - obviously, this also meets the
251          * existence check, if that was requested
252          */
253         free(fullpath);
254         return NULL;
255     }
256 
257     if (!(S_IFREG & buf.st_mode) &&
258         !(S_IFLNK & buf.st_mode)) {
259         /* this isn't a regular file or a symbolic link, so
260          * ignore it
261          */
262         free(fullpath);
263         return NULL;
264     }
265 
266     /* check the permissions */
267     if ((X_OK & mode) && !(S_IXUSR & buf.st_mode)) {
268         /* if they asked us to check executable permission,
269          * and that isn't set, then return NULL
270          */
271         free(fullpath);
272         return NULL;
273     }
274     if ((R_OK & mode) && !(S_IRUSR & buf.st_mode)) {
275         /* if they asked us to check read permission,
276          * and that isn't set, then return NULL
277          */
278         free(fullpath);
279         return NULL;
280     }
281     if ((W_OK & mode) && !(S_IWUSR & buf.st_mode)) {
282         /* if they asked us to check write permission,
283          * and that isn't set, then return NULL
284          */
285         free(fullpath);
286         return NULL;
287     }
288 
289     /* must have met all criteria! */
290     return fullpath;
291 }
292 
293 
294 /**
295  *
296  *  Loads argument array with $PATH env var.
297  *
298  *  Accepts
299  *      -path String containing the $PATH
300  *      -argc Pointer to argc
301  *      -argv Pointer to list of argv
302  */
path_env_load(char * path,int * pargc,char *** pargv)303 static void path_env_load(char *path, int *pargc, char ***pargv)
304 {
305     char *p;
306     char saved;
307 
308     if (NULL == path) {
309         *pargc = 0;
310         return;
311     }
312 
313     /* Loop through the paths (delimited by PATHENVSEP), adding each
314        one to argv. */
315 
316     while ('\0' != *path) {
317 
318         /* Locate the delimiter. */
319 
320         for (p = path; *p && (*p != PMIX_ENV_SEP); ++p) {
321             continue;
322         }
323 
324         /* Add the path. */
325 
326         if (p != path) {
327             saved = *p;
328             *p = '\0';
329             pmix_argv_append(pargc, pargv, path);
330             *p = saved;
331             path = p;
332         }
333 
334         /* Skip past the delimiter, if present. */
335 
336         if (*path) {
337             ++path;
338         }
339     }
340 }
341 
342 
343 /**
344  *  Gets value of variable in list or environment. Looks in the list first
345  *
346  *  Accepts:
347  *      -var  String variable
348  *      -list Pointer to environment list
349  *
350  *  Returns:
351  *      -List Pointer to environment list Success
352  *      -NULL Failure
353  */
list_env_get(char * var,char ** list)354 static char *list_env_get(char *var, char **list)
355 {
356     size_t n;
357 
358     if (NULL != list) {
359         n = strlen(var);
360 
361         while (NULL != *list) {
362             if ((0 == strncmp(var, *list, n)) && ('=' == (*list)[n])) {
363                 return (*list + n + 1);
364             }
365             ++list;
366         }
367     }
368     return getenv(var);
369 }
370 
371 /**
372  * Try to figure out the absolute path based on the application name
373  * (usually argv[0]). If the path is already absolute return a copy, if
374  * it start with . look into the current directory, if not dig into
375  * the $PATH.
376  * In case of error or if executable was not found (as an example if
377  * the application did a cwd between the start and this call), the
378  * function will return NULL. Otherwise, an newly allocated string
379  * will be returned.
380  */
pmix_find_absolute_path(char * app_name)381 char* pmix_find_absolute_path( char* app_name )
382 {
383     char* abs_app_name;
384     char cwd[PMIX_PATH_MAX], *pcwd;
385 
386     if( pmix_path_is_absolute(app_name) ) { /* already absolute path */
387         abs_app_name = app_name;
388     } else if ( '.' == app_name[0] ||
389                NULL != strchr(app_name, PMIX_PATH_SEP[0])) {
390         /* the app is in the current directory or below it */
391         pcwd = getcwd( cwd, PMIX_PATH_MAX );
392         if( NULL == pcwd ) {
393             /* too bad there is no way we can get the app absolute name */
394             return NULL;
395         }
396         abs_app_name = pmix_os_path( false, pcwd, app_name, NULL );
397     } else {
398         /* Otherwise try to search for the application in the PATH ... */
399         abs_app_name = pmix_path_findv( app_name, X_OK, NULL, NULL );
400     }
401 
402     if( NULL != abs_app_name ) {
403         char* resolved_path = (char*)malloc(PMIX_PATH_MAX);
404         if (NULL == realpath( abs_app_name, resolved_path )) {
405             free(resolved_path);
406             free(abs_app_name);
407             return NULL;
408         }
409         if( abs_app_name != app_name ) {
410             free(abs_app_name);
411         }
412         return resolved_path;
413     }
414     return NULL;
415 }
416 
417 /**
418  * Read real FS type from /etc/mtab, needed to translate autofs fs type into real fs type
419  * TODO: solaris? OSX?
420  * Limitations: autofs on solaris/osx will be assumed as "nfs" type
421  */
422 
pmix_check_mtab(char * dev_path)423 static char *pmix_check_mtab(char *dev_path)
424 {
425 
426 #ifdef HAVE_MNTENT_H
427     FILE * mtab = NULL;
428     struct mntent * part = NULL;
429 
430     if ((mtab = setmntent(MOUNTED_FILE, "r")) != NULL) {
431         while (NULL != (part = getmntent(mtab))) {
432             if ((NULL != part->mnt_dir) &&
433                 (NULL != part->mnt_type) &&
434                 (0 == strcmp(part->mnt_dir, dev_path)))
435             {
436                 endmntent(mtab);
437                 return strdup(part->mnt_type);
438             }
439         }
440         endmntent(mtab);
441     }
442 #endif
443     return NULL;
444 }
445 
446 
447 /**
448  * @brief Figure out, whether fname is on network file system
449  *
450  * Try to figure out, whether the file name specified through fname is
451  * on any network file system (currently NFS, Lustre, Panasas and GPFS).
452  *
453  * If the file is not created, the parent directory is checked.
454  * This allows checking for NFS prior to opening the file.
455  *
456  * @fname[in]          File name to check
457  * @fstype[out]        File system type if retval is true
458  *
459  * @retval true                If fname is on NFS, Lustre, Panasas or GPFS
460  * @retval false               otherwise
461  *
462  *
463  * Linux:
464  *   statfs(const char *path, struct statfs *buf);
465  *          with fsid_t  f_fsid;  (in kernel struct{ int val[2] };)
466  *          return 0 success, -1 on failure with errno set.
467  *   statvfs (const char *path, struct statvfs *buf);
468  *          with unsigned long  f_fsid;   -- returns wrong info
469  *          return 0 success, -1 on failure with errno set.
470  * Solaris:
471  *   statvfs (const char *path, struct statvfs *buf);
472  *          with f_basetype, contains a string of length FSTYPSZ
473  *          return 0 success, -1 on failure with errno set.
474  * FreeBSD:
475  *   statfs(const char *path, struct statfs *buf);
476  *          with f_fstypename, contains a string of length MFSNAMELEN
477  *          return 0 success, -1 on failure with errno set.
478  *          compliant with: 4.4BSD.
479  * NetBSD:
480  *   statvfs (const char *path, struct statvfs *buf);
481  *          with f_fstypename, contains a string of length VFS_NAMELEN
482  *          return 0 success, -1 on failure with errno set.
483  * Mac OSX (10.6.2 through 10.9):
484  *   statvfs(const char * restrict path, struct statvfs * restrict buf);
485  *          with fsid    Not meaningful in this implementation.
486  *          is just a wrapper around statfs()
487  *   statfs(const char *path, struct statfs *buf);
488  *          with f_fstypename, contains a string of length MFSTYPENAMELEN
489  *          return 0 success, -1 on failure with errno set.
490  */
491 #ifndef LL_SUPER_MAGIC
492 #define LL_SUPER_MAGIC                    0x0BD00BD0     /* Lustre magic number */
493 #endif
494 #ifndef NFS_SUPER_MAGIC
495 #define NFS_SUPER_MAGIC                   0x6969
496 #endif
497 #ifndef PAN_KERNEL_FS_CLIENT_SUPER_MAGIC
498 #define PAN_KERNEL_FS_CLIENT_SUPER_MAGIC  0xAAD7AAEA     /* Panasas FS */
499 #endif
500 #ifndef GPFS_SUPER_MAGIC
501 #define GPFS_SUPER_MAGIC  0x47504653    /* Thats GPFS in ASCII */
502 #endif
503 #ifndef AUTOFS_SUPER_MAGIC
504 #define AUTOFS_SUPER_MAGIC 0x0187
505 #endif
506 #ifndef PVFS2_SUPER_MAGIC
507 #define PVFS2_SUPER_MAGIC 0x20030528
508 #endif
509 
510 #define MASK2        0xffff
511 #define MASK4    0xffffffff
512 
pmix_path_nfs(char * fname,char ** ret_fstype)513 bool pmix_path_nfs(char *fname, char **ret_fstype)
514 {
515     int i;
516     int fsrc = -1;
517     int vfsrc = -1;
518     int trials;
519     char * file = strdup (fname);
520 #if defined(USE_STATFS)
521     struct statfs fsbuf;
522 #endif
523 #if defined(HAVE_STATVFS)
524     struct statvfs vfsbuf;
525 #endif
526     /*
527      * Be sure to update the test (test/util/pmix_path_nfs.c)
528      * while adding a new Network/Cluster Filesystem here
529      */
530     static struct fs_types_t {
531         unsigned long long f_fsid;
532         unsigned long long f_mask;
533         const char * f_fsname;
534     } fs_types[] = {
535         {LL_SUPER_MAGIC,                   MASK4, "lustre"},
536         {NFS_SUPER_MAGIC,                  MASK2, "nfs"},
537         {AUTOFS_SUPER_MAGIC,               MASK2, "autofs"},
538         {PAN_KERNEL_FS_CLIENT_SUPER_MAGIC, MASK4, "panfs"},
539         {GPFS_SUPER_MAGIC,                 MASK4, "gpfs"},
540         {PVFS2_SUPER_MAGIC,                MASK4, "pvfs2"}
541     };
542 #define FS_TYPES_NUM (int)(sizeof (fs_types)/sizeof (fs_types[0]))
543 
544     /*
545      * First, get the OS-dependent struct stat(v)fs buf.  This may
546      * return the ESTALE error on NFS, if the underlying file/path has
547      * changed.
548      */
549 again:
550 #if defined(USE_STATFS)
551     trials = 5;
552     do {
553         fsrc = statfs(file, &fsbuf);
554     } while (-1 == fsrc && ESTALE == errno && (0 < --trials));
555 #endif
556 #if defined(HAVE_STATVFS)
557     trials = 5;
558     do {
559         vfsrc = statvfs(file, &vfsbuf);
560     } while (-1 == vfsrc && ESTALE == errno && (0 < --trials));
561 #endif
562 
563     /* In case some error with the current filename, try the parent
564        directory */
565     if (-1 == fsrc && -1 == vfsrc) {
566         char * last_sep;
567 
568         PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: stat(v)fs on file:%s failed errno:%d directory:%s\n",
569                              fname, errno, file));
570         if (EPERM == errno) {
571             free(file);
572             if ( NULL != ret_fstype ) {
573                 *ret_fstype = NULL;
574             }
575             return false;
576         }
577 
578         last_sep = strrchr(file, PMIX_PATH_SEP[0]);
579         /* Stop the search, when we have searched past root '/' */
580         if (NULL == last_sep || (1 == strlen(last_sep) &&
581             PMIX_PATH_SEP[0] == *last_sep)) {
582             free (file);
583             if ( NULL != ret_fstype ) {
584                 *ret_fstype=NULL;
585             }
586             return false;
587         }
588         *last_sep = '\0';
589 
590         goto again;
591     }
592 
593     /* Next, extract the magic value */
594     for (i = 0; i < FS_TYPES_NUM; i++) {
595 #if defined(USE_STATFS)
596         /* These are uses of struct statfs */
597 #    if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME)
598         if (0 == fsrc &&
599             0 == strncasecmp(fs_types[i].f_fsname, fsbuf.f_fstypename,
600                              sizeof(fsbuf.f_fstypename))) {
601             goto found;
602         }
603 #    endif
604 #    if defined(HAVE_STRUCT_STATFS_F_TYPE)
605         if (0 == fsrc &&
606             fs_types[i].f_fsid == (fsbuf.f_type & fs_types[i].f_mask)) {
607             goto found;
608         }
609 #    endif
610 #endif
611 
612 #if defined(HAVE_STATVFS)
613         /* These are uses of struct statvfs */
614 #    if defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
615         if (0 == vfsrc &&
616             0 == strncasecmp(fs_types[i].f_fsname, vfsbuf.f_basetype,
617                              sizeof(vfsbuf.f_basetype))) {
618             goto found;
619         }
620 #    endif
621 #    if defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)
622         if (0 == vfsrc &&
623             0 == strncasecmp(fs_types[i].f_fsname, vfsbuf.f_fstypename,
624                              sizeof(vfsbuf.f_fstypename))) {
625             goto found;
626         }
627 #    endif
628 #endif
629     }
630 
631     free (file);
632     if ( NULL != ret_fstype ) {
633         *ret_fstype=NULL;
634     }
635     return false;
636 
637 #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || \
638     defined(HAVE_STRUCT_STATFS_F_TYPE) || \
639     defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || \
640     defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)
641   found:
642 #endif
643 
644     free (file);
645     if (AUTOFS_SUPER_MAGIC == fs_types[i].f_fsid) {
646         char *fs_type = pmix_check_mtab(fname);
647         int x;
648         if (NULL != fs_type) {
649             for (x = 0; x < FS_TYPES_NUM; x++) {
650                 if (AUTOFS_SUPER_MAGIC == fs_types[x].f_fsid) {
651                     continue;
652                 }
653                 if (0 == strcasecmp(fs_types[x].f_fsname, fs_type)) {
654                     PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: file:%s on fs:%s\n", fname, fs_type));
655                     free(fs_type);
656                     if ( NULL != ret_fstype ) {
657                         *ret_fstype = strdup(fs_types[x].f_fsname);
658                     }
659                     return true;
660                 }
661             }
662             free(fs_type);
663             if ( NULL != ret_fstype ) {
664                 *ret_fstype=NULL;
665             }
666             return false;
667         }
668     }
669 
670     PMIX_OUTPUT_VERBOSE((10, 0, "pmix_path_nfs: file:%s on fs:%s\n",
671                 fname, fs_types[i].f_fsname));
672     if ( NULL != ret_fstype ) {
673         *ret_fstype = strdup (fs_types[i].f_fsname);
674     }
675     return true;
676 
677 #undef FS_TYPES_NUM
678 }
679 
680 int
pmix_path_df(const char * path,uint64_t * out_avail)681 pmix_path_df(const char *path,
682              uint64_t *out_avail)
683 {
684     int rc = -1;
685     int trials = 5;
686     int err = 0;
687 #if defined(USE_STATFS)
688     struct statfs buf;
689 #elif defined(HAVE_STATVFS)
690     struct statvfs buf;
691 #endif
692 
693     if (NULL == path || NULL == out_avail) {
694         return PMIX_ERROR;
695     }
696     *out_avail = 0;
697 
698     do {
699 #if defined(USE_STATFS)
700         rc = statfs(path, &buf);
701 #elif defined(HAVE_STATVFS)
702         rc = statvfs(path, &buf);
703 #endif
704         err = errno;
705     } while (-1 == rc && ESTALE == err && (--trials > 0));
706 
707     if (-1 == rc) {
708         PMIX_OUTPUT_VERBOSE((10, 2, "pmix_path_df: stat(v)fs on "
709                              "path: %s failed with errno: %d (%s)\n",
710                              path, err, strerror(err)));
711         return PMIX_ERROR;
712     }
713 
714     /* now set the amount of free space available on path */
715                                /* sometimes buf.f_bavail is negative */
716     *out_avail = buf.f_bsize * ((int)buf.f_bavail < 0 ? 0 : buf.f_bavail);
717 
718     PMIX_OUTPUT_VERBOSE((10, 2, "pmix_path_df: stat(v)fs states "
719                          "path: %s has %"PRIu64 " B of free space.",
720                          path, *out_avail));
721 
722     return PMIX_SUCCESS;
723 }
724