#include <sys/types.h>
#include <sys/mount.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "server.h"
jmp_buf env;
char *
find_file(char *pathname, struct stat *statbuf, int *isvalid)
{
static char last_pathname[PATH_MAX];
static char file[PATH_MAX + 3];
static struct stat filestat;
char *p;
*isvalid = 0;
if (strcmp(pathname, last_pathname) == 0 && file[0]) {
if (statbuf)
statbuf = &filestat;
if (strcmp(pathname, file) == 0)
*isvalid = 1;
return(file);
}
if (strlen(pathname) > sizeof(file) + 3) {
error("%s: Name to large for buffer.", pathname);
return(NULL);
}
(void) strlcpy(last_pathname, pathname, sizeof(last_pathname));
if (*pathname == '/')
(void) strlcpy(file, pathname, sizeof(file));
else {
(void) strlcpy(file, "./", sizeof(file));
(void) strlcat(file, pathname, sizeof(file));
}
while (lstat(file, &filestat) != 0) {
if (errno == ENOENT) {
if ((p = strrchr(file, '/')) != NULL) {
if (strcmp(p, "/.") == 0) {
*p = CNULL;
} else {
*++p = '.';
*++p = CNULL;
}
} else {
debugmsg(DM_MISC, "Cannot find dir of `%s'",
pathname);
return(NULL);
}
continue;
} else {
error("%s: lstat failed: %s", pathname, SYSERR);
return(NULL);
}
}
if (statbuf)
bcopy(&filestat, statbuf, sizeof(filestat));
p = &file[strlen(file) - 1];
if (*p == '.')
*p-- = CNULL;
for ( ; p && *p && *p == '/' && p != file; --p)
*p = CNULL;
if (S_ISLNK(filestat.st_mode))
if ((p = strrchr(file, '/')) && *p+1) {
if (p == file)
file[1] = CNULL;
else
*p = CNULL;
}
if (strcmp(pathname, file) == 0)
*isvalid = 1;
return(*file ? file : NULL);
}
mntent_t *
findmnt(struct stat *filest, struct mntinfo *mntinfo)
{
struct mntinfo *mi;
for (mi = mntinfo; mi; mi = mi->mi_nxt) {
if (mi->mi_mnt->me_flags & MEFLAG_IGNORE)
continue;
if (filest->st_dev == mi->mi_dev)
return(mi->mi_mnt);
}
return(NULL);
}
int
isdupmnt(mntent_t *mnt, struct mntinfo *mntinfo)
{
struct mntinfo *m;
for (m = mntinfo; m; m = m->mi_nxt)
if (strcmp(m->mi_mnt->me_path, mnt->me_path) == 0)
return(1);
return(0);
}
void
wakeup(int dummy)
{
debugmsg(DM_CALL, "wakeup() in filesys.c called");
longjmp(env, 1);
}
struct mntinfo *
makemntinfo(struct mntinfo *mi)
{
static struct mntinfo *mntinfo;
struct mntinfo *newmi, *m;
struct stat mntstat;
mntent_t *mnt;
int timeo = 310;
if (!setmountent()) {
message(MT_NERROR, "setmntent failed: %s", SYSERR);
return(NULL);
}
(void) signal(SIGALRM, wakeup);
(void) alarm(timeo);
if (setjmp(env)) {
message(MT_NERROR, "Timeout getting mount info");
return(NULL);
}
mntinfo = mi;
while ((mnt = getmountent()) != NULL) {
debugmsg(DM_MISC, "mountent = '%s'", mnt->me_path);
if (isdupmnt(mnt, mntinfo))
continue;
if (stat(mnt->me_path, &mntstat) != 0) {
message(MT_WARNING, "%s: Cannot stat filesystem: %s",
mnt->me_path, SYSERR);
continue;
}
newmi = xcalloc(1, sizeof(*newmi));
newmi->mi_mnt = newmountent(mnt);
newmi->mi_dev = mntstat.st_dev;
if (mntinfo) {
for (m = mntinfo; m->mi_nxt; m = m->mi_nxt)
continue;
m->mi_nxt = newmi;
} else
mntinfo = newmi;
}
alarm(0);
endmountent();
return(mntinfo);
}
mntent_t *
getmntpt(char *pathname, struct stat *statbuf, int *isvalid)
{
static struct mntinfo *mntinfo = NULL;
static struct stat filestat;
struct stat *pstat;
struct mntinfo *tmpmi;
mntent_t *mnt;
if (statbuf)
pstat = statbuf;
else
pstat = &filestat;
if (!find_file(pathname, pstat, isvalid))
return(NULL);
if (!mntinfo)
mntinfo = makemntinfo(NULL);
if ((mnt = findmnt(pstat, mntinfo)) != NULL)
return(mnt);
if ((tmpmi = makemntinfo(mntinfo)) != NULL) {
mntinfo = tmpmi;
if ((mnt = findmnt(pstat, mntinfo)) != NULL)
return(mnt);
}
error("%s: Could not find mount point", pathname);
return(NULL);
}
int
is_nfs_mounted(char *path, struct stat *statbuf, int *isvalid)
{
mntent_t *mnt;
if ((mnt = getmntpt(path, statbuf, isvalid)) == NULL)
return(-1);
if (mnt->me_flags & MEFLAG_NFS)
return(1);
return(0);
}
int
is_ro_mounted(char *path, struct stat *statbuf, int *isvalid)
{
mntent_t *mnt;
if ((mnt = getmntpt(path, statbuf, isvalid)) == NULL)
return(-1);
if (mnt->me_flags & MEFLAG_READONLY)
return(1);
return(0);
}
int
is_symlinked(char *path, struct stat *statbuf, int *isvalid)
{
static struct stat stb;
if (!(*isvalid)) {
if (lstat(path, &stb) != 0)
return(-1);
statbuf = &stb;
}
if (S_ISLNK(statbuf->st_mode))
return(1);
return(0);
}
int
getfilesysinfo(char *file, int64_t *freespace, int64_t *freefiles)
{
struct statfs statfsbuf;
char *mntpt;
int64_t val;
int t, r;
mntpt = find_file(file, NULL, &t);
if (!mntpt) {
debugmsg(DM_MISC, "unknown mount point for `%s'", file);
return(-1);
}
r = statfs(mntpt, &statfsbuf);
if (r < 0) {
error("%s: Cannot statfs filesystem: %s.", mntpt, SYSERR);
return(-1);
}
val = -1;
if (statfsbuf.f_bavail >= 0)
val = (statfsbuf.f_bavail * (statfsbuf.f_bsize / 512)) / 2;
*freespace = val;
val = -1;
if (statfsbuf.f_favail >= 0)
val = statfsbuf.f_favail;
*freefiles = val;
return(0);
}