Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using stat to determine programmatically whether a file is a mount point.
#include <assert.h>
#include <sys/stat.h>
#include <stdint.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
struct stat file_stat;
struct stat parent_stat;
char * file_name;
char * parent_name;
assert(argc == 2);
file_name = argv[1];
/* get the parent directory of the file */
parent_name = dirname(file_name);
/* get the file's stat info */
if( -1 == stat(file_name, &file_stat) ) {
perror("Stat: ");
goto fail;
}
/* determine whether the supplied file is a directory
if it isn't, then it can't be a mountpoint. */
if( !(file_stat.st_mode & S_IFDIR) ) {
printf("%s is not a directory.\n", file_name);
goto fail;
}
/* get the parent's stat info */
if( -1 == stat(parent_name, &parent_stat) ) {
perror("Stat: ");
goto fail;
}
/* print out device ids and inodes for each file */
printf("Parent directory: %s\n", parent_name);
printf("Files's dev ID: %u\n", file_stat.st_dev);
printf("Parent's dev ID: %u\n", parent_stat.st_dev);
printf("Files's inode: %llu\n", (uint64_t)file_stat.st_ino);
printf("Parent's inode: %llu\n", (uint64_t)parent_stat.st_ino);
/* if file and parent have different device ids,
then the file is a mount point
or, if they refer to the same file,
then it's probably the root directory '/'
and therefore a mountpoint */
if( file_stat.st_dev != parent_stat.st_dev ||
( file_stat.st_dev == parent_stat.st_dev &&
file_stat.st_ino == parent_stat.st_ino
)
) {
printf("%s IS a mountpoint.\n", file_name);
} else {
printf("%s is NOT a mountpoint.\n", file_name);
}
free(parent_name);
return 0;
fail:
free(parent_name);
return 1;
}
@vinayven
Copy link

vinayven commented Apr 7, 2016

Bug in the code:

Freeing un-allocated ptr parent_name in lines 64 and 69. We supply file_name as a command line argument and make the char* file_name ptr point to this. From my knowledge of the allocation of memory, kernel puts the args above the main's stack and inside main, we make the pointer point to it. So there is no dynamically allocated memory here. So freeing un-allocated memory results in an obvious seg fault.

@vinayven
Copy link

vinayven commented Apr 8, 2016

That code below would be the correct code. dirname modifies the file and makes the parent point to the same string. So no allocations happen here. The original code thus ends up stating the same file path for both itself and the parent. The code above works.

@vinayven
Copy link

vinayven commented Apr 8, 2016

include <assert.h>

include <sys/stat.h>

include <stdint.h>

include <libgen.h>

include <stdio.h>

include <stdlib.h>

include <string.h>

int main(int argc, char * argv[]) {

struct stat file_stat;
struct stat parent_stat;
char * file_name;
char * parent_name;
char* orig_name;

assert(argc == 2);

file_name = argv[1];
orig_name = (char*)malloc(strlen(file_name) + 1);
memcpy(orig_name, file_name, strlen(file_name) + 1);
printf("orig_name = %s\n", orig_name);

// get the parent directory of the file
parent_name = dirname(orig_name);
printf("file name = %s\n", file_name);

// get the file's stat info
if( -1 == stat(file_name, &file_stat) ) {
perror("Stat: ");
goto fail;
}

//determine whether the supplied file is a directory
// if it isn't, then it can't be a mountpoint.
if( !(file_stat.st_mode & S_IFDIR) ) {
printf("%s is not a directory.\n", file_name);
goto fail;
}

// get the parent's stat info
if( -1 == stat(parent_name, &parent_stat) ) {
perror("Stat: ");
goto fail;
}

//print out device ids and inodes for each file
printf("Parent directory: %s\n", parent_name);
printf("Files's dev ID: %u\n", file_stat.st_dev);
printf("Parent's dev ID: %u\n", parent_stat.st_dev);
printf("Files's inode: %llu\n", (uint64_t)file_stat.st_ino);
printf("Parent's inode: %llu\n", (uint64_t)parent_stat.st_ino);

// if file and parent have different device ids,
// then the file is a mount point
// or, if they refer to the same file,
// then it's probably the root directory
// and therefore a mountpoint
if( file_stat.st_dev != parent_stat.st_dev ||
( file_stat.st_dev == parent_stat.st_dev &&
file_stat.st_ino == parent_stat.st_ino ) ) {
printf("%s IS a mountpoint.\n", file_name);
} else {
printf("%s is NOT a mountpoint.\n", file_name);
}

// Free the malloc'ed pointer.
free(orig_name);
return 0;

fail:
free(orig_name);
return 1;

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment