/* * 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 #endif #include "misc/types.h" #include "util/device.h" #include #include #include #include #include #include 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; }