1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9 #include "libbb.h"
10 #include <mntent.h>
11 
12 /*
13  * Given a block device, find the mount table entry if that block device
14  * is mounted.
15  *
16  * Given any other file (or directory), find the mount table entry for its
17  * filesystem.
18  */
find_mount_point(const char * name,int subdir_too)19 struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
20 {
21 	struct stat s;
22 	FILE *mtab_fp;
23 	struct mntent *mountEntry;
24 	dev_t devno_of_name;
25 	bool block_dev;
26 
27 	if (stat(name, &s) != 0)
28 		return NULL;
29 
30 	devno_of_name = s.st_dev;
31 	block_dev = 0;
32 	/* Why S_ISCHR? - UBI volumes use char devices, not block */
33 	if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) {
34 		devno_of_name = s.st_rdev;
35 		block_dev = 1;
36 	}
37 
38 	mtab_fp = setmntent(bb_path_mtab_file, "r");
39 	if (!mtab_fp)
40 		return NULL;
41 
42 	while ((mountEntry = getmntent(mtab_fp)) != NULL) {
43 		/* rootfs mount in Linux 2.6 exists always,
44 		 * and it makes sense to always ignore it.
45 		 * Otherwise people can't reference their "real" root! */
46 		if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0)
47 			continue;
48 
49 		if (strcmp(name, mountEntry->mnt_dir) == 0
50 		 || strcmp(name, mountEntry->mnt_fsname) == 0
51 		) { /* String match. */
52 			break;
53 		}
54 
55 		if (!(subdir_too || block_dev))
56 			continue;
57 
58 		/* Is device's dev_t == name's dev_t? */
59 		if (mountEntry->mnt_fsname[0] == '/'
60 		/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
61 		 * avoid stat'ing "sysfs", "proc", "none" and such,
62 		 * useless at best, can stat unrelated files at worst.
63 		 */
64 		 && stat(mountEntry->mnt_fsname, &s) == 0
65 		 && s.st_rdev == devno_of_name
66 		) {
67 			break;
68 		}
69 		/* Match the directory's mount point. */
70 		if (stat(mountEntry->mnt_dir, &s) == 0
71 		 && s.st_dev == devno_of_name
72 		) {
73 			break;
74 		}
75 	}
76 	endmntent(mtab_fp);
77 
78 	return mountEntry;
79 }
80