How can I check whether a given path (absolute or relative) specifies the root directory of a volume with POSIX or standard C runtime calls? Ideally, the code should work on both, Linux and Mac OS X.
How to check if a path specifies a volume root directory
1.5k Views Asked by Andreas AtThere are 3 best solutions below

Well, you have several ways. Historically, the root inode has had inum of 2
, so just stat(path, &buf);
and check if (buf.st_ino == 2)
.
Recently, with proliferation of different filesystem types, there's no warranty of having inum equal to 2
in the root inode, so you must follow a different approach: Just check if the given path and the parent directory (just append "/.."
to path) reside in different devices (st_dev
field of struct stat
info)
The following code illustrates this:
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
int is_mount(char *path)
{
struct stat sdir; /* inode info */
struct stat spdir; /* parent inode info */
char buffer[PATH_MAX];
int res = stat(path, &sdir);
if (res < 0) return -1;
if (snprintf(buffer, sizeof buffer, "%s/..", path) >= sizeof buffer) {
errno = ENAMETOOLONG;
return -1;
}
res = stat(buffer, &spdir);
if (res < 0) return -1;
return sdir.st_dev != spdir.st_dev; /* SEE ADDITIONAL NOTE */
}
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++) {
int res = is_mount(argv[i]);
if ( res < 0 ) {
fprintf(stderr,
"%s: %s (errno = %d)\n",
argv[i], strerror(errno), errno);
continue;
}
printf("%5s\t%s\n", res ? "true" : "false", argv[i]);
} /* for */
} /* main */
Execution on a FreeBSD system:
$ ismount /home/luis/usr.ports/german/geonext/Makefile /home/luis/usr.ports/german/geonext /home/luis/usr.ports/german /home/luis/usr.ports /home/luis /home / /var/run/cups /var/run /var pru3.c
/home/luis/usr.ports/german/geonext/Makefile: Not a directory (errno = 20)
pru3.c: Not a directory (errno = 20)
false /home/luis/usr.ports/german/geonext
false /home/luis/usr.ports/german
true /home/luis/usr.ports
false /home/luis
false /home
true / <-- in the above code, this returns false, see ADDITIONAL NOTE.
false /var/run/cups
true /var/run
false /var
PORTABILITY NOTE
This should work in any un*x/linux that implements the stat(2)
system call. UNIX v7 already implements this, so it's supposed to be found in all unices available.
ADDITIONAL NOTE
This approach does not work for the actual filesystem root (/
) because the parent dir and the root dir both point to the same inode. This can be solved by checking the st_ino
of both parent and child inodes to be equal. Just change the test for
return (sdir.st_dev != spdir.st_dev) /* different devices */
|| ( /* sdir.st_dev == spdir.st_dev && ---redundant */
sdir.st_ino == spdir.st_ino); /* root dir case */

POSIX has a realpath
function that returns the canonical path of any given path (thus eliminating/resolving dots, dotdots, links, etc).
Now POSIX doesn't define volume, only the hierarchy of filenames from a unique given root /
. Now Unix variants are able to mount file trees one on top of other to obtain a single tree at runtime. There is no standard way to "mount" these volumes, even if mount
is a very common way, because there is plenty of ways to realize this feature. So you have to read the documentation of your OS variant to determine how you can obtain the list of all mounted points.
You may also read Linux function to get mount points and How to get mount point information from an API on Mac?.
First, all you can really check using standard functions is if the path presented is a mount point, and that mount point may or may not be the root of its filesystem.
Assuming your system assigns a unique
f_fsid
value to each mount point, you can use the POSIX-stanardstatvfs()
function and compare thef_fsid
field of the relevantstatvfs
structure of the path component with its parent:All error checking is left as an exercise (and it would also make this example longer and harder to understand...).
If the
f_fsid
of a path differs from its parent'sf_fsid
, or if the path is the root directory itself, the path passed in must be the mount point of its filesystem. Note that this does not have to be the actual root of the filesystem. For example, a host can export a file system via NFS, and an NFS client can mount any subdirectory in the remote file system as the "local root", or a loopback mount can refer to a subdirectory of another filesystem.