#include "src/include/pmix_config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SHLWAPI_H
# include <shlwapi.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
# include <sys/mount.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_VFS_H
# include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
# include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#ifdef HAVE_MNTENT_H
# include <mntent.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef _PATH_MOUNTED
# define MOUNTED_FILE _PATH_MOUNTED
#else
# define MOUNTED_FILE "/etc/mtab"
#endif
#include "src/include/pmix_globals.h"
#include "src/include/pmix_stdint.h"
#include "src/util/pmix_argv.h"
#include "src/util/pmix_basename.h"
#include "src/util/pmix_os_path.h"
#include "src/util/pmix_output.h"
#include "src/util/pmix_path.h"
#if !defined(HAVE_STATFS) && !defined(HAVE_STATVFS)
# error Must have either statfs() or statvfs()
#endif
#if defined(HAVE_STATFS) \
&& (defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(HAVE_STRUCT_STATFS_F_TYPE))
# define USE_STATFS 1
#endif
static void path_env_load(char *path, int *pargc, char ***pargv);
static char *list_env_get(char *var, char **list);
bool pmix_path_is_absolute(const char *path)
{
if (PMIX_PATH_SEP[0] == *path) {
return true;
}
return false;
}
char *pmix_path_find(char *fname, char **pathv, int mode, char **envv)
{
char *fullpath;
char *delimit;
char *env;
char *pfix;
int i;
if (pmix_path_is_absolute(fname)) {
return pmix_path_access(fname, NULL, mode);
}
fullpath = NULL;
i = 0;
while (pathv[i] && NULL == fullpath) {
if ('$' == *pathv[i]) {
delimit = strchr(pathv[i], PMIX_PATH_SEP[0]);
if (delimit) {
*delimit = '\0';
}
env = list_env_get(pathv[i] + 1, envv);
if (delimit) {
*delimit = PMIX_PATH_SEP[0];
}
if (NULL != env) {
if (!delimit) {
fullpath = pmix_path_access(fname, env, mode);
} else {
pfix = (char *) malloc(strlen(env) + strlen(delimit) + 1);
if (NULL == pfix) {
return NULL;
}
strcpy(pfix, env);
strcat(pfix, delimit);
fullpath = pmix_path_access(fname, pfix, mode);
free(pfix);
}
}
} else {
fullpath = pmix_path_access(fname, pathv[i], mode);
}
i++;
}
return pmix_make_filename_os_friendly(fullpath);
}
char *pmix_path_findv(char *fname, int mode, char **envv, char *wrkdir)
{
char **dirv;
char *fullpath;
char *path;
int dirc;
int i;
bool found_dot = false;
dirc = 0;
dirv = NULL;
if (NULL != (path = list_env_get("PATH", envv))) {
path_env_load(path, &dirc, &dirv);
}
if (NULL != wrkdir) {
for (i = 0; i < dirc; ++i) {
if (0 == strcmp(dirv[i], ".")) {
found_dot = true;
free(dirv[i]);
dirv[i] = strdup(wrkdir);
if (NULL == dirv[i]) {
return NULL;
}
}
}
}
if (!found_dot && NULL != wrkdir) {
pmix_argv_append(&dirc, &dirv, wrkdir);
}
if (NULL == dirv) {
return NULL;
}
fullpath = pmix_path_find(fname, dirv, mode, envv);
PMIx_Argv_free(dirv);
return fullpath;
}
char *pmix_path_access(char *fname, char *path, int mode)
{
char *fullpath = NULL;
if (NULL == path) {
fullpath = pmix_os_path(false, fname, NULL);
} else {
fullpath = pmix_os_path(false, path, fname, NULL);
}
if (NULL == fullpath)
return NULL;
if (0 != access(fullpath, mode)) {
free(fullpath);
return NULL;
}
return fullpath;
}
static void path_env_load(char *path, int *pargc, char ***pargv)
{
char *p;
char saved;
if (NULL == path) {
*pargc = 0;
return;
}
while ('\0' != *path) {
for (p = path; *p && (*p != PMIX_ENV_SEP); ++p) {
continue;
}
if (p != path) {
saved = *p;
*p = '\0';
pmix_argv_append(pargc, pargv, path);
*p = saved;
path = p;
}
if (*path) {
++path;
}
}
}
static char *list_env_get(char *var, char **list)
{
size_t n;
if (NULL != list) {
n = strlen(var);
while (NULL != *list) {
if ((0 == strncmp(var, *list, n)) && ('=' == (*list)[n])) {
return (*list + n + 1);
}
++list;
}
}
return getenv(var);
}
char *pmix_find_absolute_path(char *app_name)
{
char *abs_app_name;
char cwd[PMIX_PATH_MAX], *pcwd;
if (pmix_path_is_absolute(app_name)) {
abs_app_name = app_name;
} else if ('.' == app_name[0] || NULL != strchr(app_name, PMIX_PATH_SEP[0])) {
pcwd = getcwd(cwd, PMIX_PATH_MAX);
if (NULL == pcwd) {
return NULL;
}
abs_app_name = pmix_os_path(false, pcwd, app_name, NULL);
} else {
abs_app_name = pmix_path_findv(app_name, X_OK, NULL, NULL);
}
if (NULL != abs_app_name) {
char *resolved_path = (char *) malloc(PMIX_PATH_MAX);
if (NULL == realpath(abs_app_name, resolved_path)) {
free(resolved_path);
free(abs_app_name);
return NULL;
}
if (abs_app_name != app_name) {
free(abs_app_name);
}
return resolved_path;
}
return NULL;
}
bool pmix_path_nfs(char *fname, char **fstype)
{
#ifdef HAVE_MNTENT_H
struct stat s;
struct mntent mnt;
FILE *fp;
dev_t dev;
char buf[1024];
int fd, n;
char* fs_types[] = {
"lustre",
"nfs",
"autofs",
"panfs",
"gpfs",
"pvfs2",
NULL
};
char *parent;
fd = open(fname, O_RDONLY);
if (0 > fd) {
parent = pmix_dirname(fname);
fd = open(parent, O_RDONLY);
free(parent);
if (0 > fd) {
return false;
}
}
if (fstat(fd, &s) != 0) {
return false;
}
close(fd);
dev = s.st_dev;
if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
if ((fp = setmntent("/etc/mtab", "r")) == NULL) {
return false;
}
}
while (getmntent_r(fp, &mnt, buf, sizeof(buf))) {
fd = open(mnt.mnt_dir, O_RDONLY);
if (0 > fd) {
continue;
}
if (fstat(fd, &s) != 0) {
close(fd);
continue;
}
if (s.st_dev == dev) {
*fstype = strdup(mnt.mnt_type);
close(fd);
endmntent(fp);
for (n=0; NULL != fs_types[n]; n++) {
if (0 == strcmp(fs_types[n], mnt.mnt_type)) {
return true;
}
}
return false;
}
close(fd);
}
endmntent(fp);
return false;
#else
PMIX_HIDE_UNUSED_PARAMS(fname, fstype);
*fstype = strdup("unknown");
return false;
#endif
}
int pmix_path_df(const char *path, uint64_t *out_avail)
{
int rc = -1;
int trials = 5;
int err = 0;
#if defined(USE_STATFS)
struct statfs buf;
#elif defined(HAVE_STATVFS)
struct statvfs buf;
#endif
if (NULL == path || NULL == out_avail) {
return PMIX_ERROR;
}
*out_avail = 0;
do {
#if defined(USE_STATFS)
rc = statfs(path, &buf);
#elif defined(HAVE_STATVFS)
rc = statvfs(path, &buf);
#endif
err = errno;
} while (-1 == rc && ESTALE == err && (--trials > 0));
if (-1 == rc) {
pmix_output_verbose(10, 2,
"pmix_path_df: stat(v)fs on "
"path: %s failed with errno: %d (%s)\n",
path, err, strerror(err));
return PMIX_ERROR;
}
*out_avail = buf.f_bsize * ((int) buf.f_bavail < 0 ? 0 : buf.f_bavail);
pmix_output_verbose(10, 2,
"pmix_path_df: stat(v)fs states "
"path: %s has %" PRIu64 " B of free space.",
path, *out_avail);
return PMIX_SUCCESS;
}