Start 1.33.0 development cycle
[oweals/busybox.git] / libbb / find_mount_point.c
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  */
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 }