165 lines
3.5 KiB
C
165 lines
3.5 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
/* Lookup the @file in the @mntfile. @file is mntent.mnt_fsname if @fsname
|
|
is set; mntent.mnt_dir otherwise. Return the mnt entry from the @mntfile.
|
|
|
|
Warning: if the root fs is mounted RO, the content of /etc/mtab may be
|
|
not correct. */
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "misc/types.h"
|
|
#include "util/device.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/vfs.h>
|
|
#include <mntent.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
static struct mntent *util_mntent_lookup(char *mntfile,
|
|
char *file,
|
|
int path)
|
|
{
|
|
struct mntent *mnt;
|
|
int name_match = 0;
|
|
struct stat st;
|
|
dev_t rdev = 0;
|
|
dev_t dev = 0;
|
|
ino_t ino = 0;
|
|
char *name;
|
|
FILE *fp;
|
|
|
|
assert(mntfile != NULL);
|
|
assert(file != NULL);
|
|
|
|
if (stat(file, &st) == 0) {
|
|
/* Devices is stated. */
|
|
if (S_ISBLK(st.st_mode)) {
|
|
rdev = st.st_rdev;
|
|
} else {
|
|
dev = st.st_dev;
|
|
ino = st.st_ino;
|
|
}
|
|
}
|
|
|
|
if ((fp = setmntent(mntfile, "r")) == NULL)
|
|
return INVAL_PTR;
|
|
|
|
while ((mnt = getmntent(fp)) != NULL) {
|
|
/* Check if names match. */
|
|
name = path ? mnt->mnt_dir : mnt->mnt_fsname;
|
|
|
|
if (strcmp(file, name) == 0)
|
|
name_match = 1;
|
|
|
|
if (stat(name, &st))
|
|
continue;
|
|
|
|
/* If names do not match, check if stats match. */
|
|
if (!name_match) {
|
|
if (rdev && S_ISBLK(st.st_mode)) {
|
|
if (rdev != st.st_rdev)
|
|
continue;
|
|
} else if (dev && !S_ISBLK(st.st_mode)) {
|
|
if (dev != st.st_dev ||
|
|
ino != st.st_ino)
|
|
continue;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* If not path and not block device do not check anything more. */
|
|
if (!path && !rdev)
|
|
break;
|
|
|
|
if (path) {
|
|
/* Either names or stats match. Make sure the st_dev of
|
|
the path is same as @mnt_fsname device rdev. */
|
|
if (stat(mnt->mnt_fsname, &st) == 0 &&
|
|
dev == st.st_rdev)
|
|
break;
|
|
} else {
|
|
/* Either names or stats match. Make sure the st_dev of
|
|
the mount entry is same as the given device rdev. */
|
|
if (stat(mnt->mnt_dir, &st) == 0 &&
|
|
rdev == st.st_dev)
|
|
break;
|
|
}
|
|
}
|
|
|
|
endmntent (fp);
|
|
return mnt;
|
|
}
|
|
|
|
struct mntent *util_mntent(char *device) {
|
|
int proc = 0, path = 0, root = 0;
|
|
|
|
struct mntent *mnt;
|
|
struct statfs stfs;
|
|
|
|
assert(device != NULL);
|
|
|
|
/* Check if the root. */
|
|
if (util_root_mounted(device) == 1)
|
|
root = 1;
|
|
|
|
#ifdef __linux__
|
|
/* Check if /proc is procfs. */
|
|
if (statfs("/proc", &stfs) == 0 && stfs.f_type == 0x9fa0) {
|
|
proc = 1;
|
|
|
|
if (root) {
|
|
/* Lookup the "/" entry in /proc/mounts. Special
|
|
case as root entry can present as:
|
|
rootfs / rootfs rw 0 0
|
|
Look up the mount point in this case. */
|
|
mnt = util_mntent_lookup("/proc/mounts", "/", 1);
|
|
} else {
|
|
/* Lookup the @device /proc/mounts */
|
|
mnt = util_mntent_lookup("/proc/mounts", device, 0);
|
|
}
|
|
|
|
if (mnt == INVAL_PTR)
|
|
proc = 0;
|
|
else if (mnt)
|
|
return mnt;
|
|
}
|
|
#endif /* __linux__ */
|
|
|
|
#if defined(MOUNTED) || defined(_PATH_MOUNTED)
|
|
|
|
#ifndef MOUNTED
|
|
#define MOUNTED _PATH_MOUNTED
|
|
#endif
|
|
/* Check in MOUNTED (/etc/mtab) if RW. */
|
|
if (!util_file_ro(MOUNTED)) {
|
|
path = 1;
|
|
|
|
if (root) {
|
|
mnt = util_mntent_lookup(MOUNTED, "/", 1);
|
|
} else {
|
|
mnt = util_mntent_lookup(MOUNTED, device, 0);
|
|
}
|
|
|
|
if (mnt == INVAL_PTR)
|
|
path = 0;
|
|
else if (mnt)
|
|
return mnt;
|
|
}
|
|
#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
|
|
|
|
/* If has not been checked in neither /proc/mounts nor /etc/mtab (or
|
|
errors have occured), return INVAL_PTR, NULL otherwise. */
|
|
return (!proc && !path) ? INVAL_PTR : NULL;
|
|
}
|
|
|