Linux – How to determine whether a linux filesystem belongs to a running system or not

directory-structurelinux

I need to write a program that receives a block device as input, like /dev/sda1, and has to perform a set of operations depending on if the filesystem inside are currently running or not.

We'll assume the input will always has a correct linux directory tree, the only I need to know is if there's a particular directory structure or file/s that can reliably determine whether the system inside is running. I mean whether the filesystem contains the root of a system that is powered on.

It should work for any filesystem or linux kernel version.

Thanks!

Best Answer

I’ve written a function that returns 1 if the argument is the root device, 0 if it is not, and a negative value for error:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

static int
root_check(const char *disk_dev)
{
        static const char  root_dir[] = "/";
        struct stat        root_statb;
        struct stat        dev_statb;

        if (stat(root_dir, &root_statb) != 0)
        {
                perror(root_dir);
                return -1;
        }
        if (!S_ISDIR(root_statb.st_mode))
        {
                fprintf(stderr, "Error: %s is not a directory!\n", root_dir);
                return -2;
        }
        if (root_statb.st_ino <= 0)
        {
                fprintf(stderr, "Warning: %s inode number is %d; "
                                "unlikely to be valid.\n",
                                        root_dir, root_statb.st_ino);
        }
        else if (root_statb.st_ino > 2)
        {
                fprintf(stderr, "Warning: %s inode number is %d; "
                                "probably not a root inode.\n",
                                        root_dir, root_statb.st_ino);
        }
        if (stat(disk_dev, &dev_statb) != 0)
        {
                perror(disk_dev);
                return -1;
        }
        if (S_ISBLK(dev_statb.st_mode))
                /* That's good. */ ;
        else if (S_ISCHR(dev_statb.st_mode))
        {
                fprintf(stderr, "Warning: %s is a character-special device; "
                                "might not be a disk.\n", disk_dev);
        }
        else
        {
                fprintf(stderr, "Warning: %s is not a device.\n", disk_dev);
                return(0);
        }
        if (dev_statb.st_rdev == root_statb.st_dev)
        {
                printf("It looks like %s is the root file system (%s).\n",
                                        disk_dev, root_dir);
                return(1);
        }
        // else
        printf("(It looks like %s is NOT the root file system.)\n", disk_dev);
        return(0);
}

The first two tests are basically sanity checks: if stat("/", …) fails or “/” is not a directory, your filesystem is broken.  The st_ino tests are something of a shot in the dark. AFAIK, inode numbers should never be negative or zero.  Historically (by which I mean 30 years ago), the root directory always had inode number 1.  This may still be true for a few flavors of *nix (anybody heard of “Minix”?), and it may be true for the special filesystems, like /proc, and for Windows (FAT) filesystems, but most contemporary Unix and Unix-like systems seem to use inode number 1 for tracking bad blocks, pushing the root up to inode number 2.

S_ISBLK is true for “block devices”, like /dev/sda1, where the output from ls -l begins with “b”.  Likewise, S_ISCHR is true for “character devices”, where the output from ls -l begins with “c”.  (You may occasionally see disk names like /dev/rsda1; the “r” stands for “raw”.  Raw disk devices are sometimes used for fsck and backup, but not mounting.)  Every inode has a st_dev, which says what filesystem that inode is on.  Inodes for devices also have st_rdev fields, which say what device they are.  (The two comma-separated numbers you see in place of the file size when you ls -l a device are the two bytes of st_rdev.)

So, the trick is to see whether the st_rdev of the disk device matches the st_dev of the root directory; i.e., is the specified device the one that “/” is on?

Related Question