3

First, a little background information to provide some motivation for this question: I've got a program that runs on a headless Linux server and reads/writes files on several removable external hard drives, each of which is formatted with ext4 filesystem. Very occasionally, the filesystem metadata on one of these drives gets corrupted for whatever reason (ext4 journalling notwithstanding), which can cause the ext4 filesystem drive to detect a problem and remount the partition as read-only, presumably as a precaution against cascading errors corrupting the drive further.

Okay, fair enough; but what I'd like to do now is add a function to my program that can detect when the drive is in this remounted-read-only state, so that it can pro-actively notify the user that his drive is in trouble.

My question is, what is an elegant/supported way to query a filesystem to find out if it is mounted read-only?

Attempting to write a file to the filesystem isn't good enough, because that could fail for other reasons, and also because I don't want to write to the filesystem if I don't have to.

My program could fopen("/proc/mounts", "r") and parse the lines of text that it generates (grepping for the "rw," token on the line corresponding to my partition), and I will if I have to, but that solution seems a bit hacky (too much like screen-scraping, liable to break if the text format ever changes).

So, is there some lightweight/purpose-built Linux system call that I could use that would tell me whether a given filesystem mount point (e.g. "/dev/sda1") is currently mounted read-only? It seems like stat() might be able to do it, but I can't see how.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • 8
    There is even a POSIX.1 function to do this: [`statvfs()` or `fstatvfs()`](http://man7.org/linux/man-pages/man3/statvfs.3.html) on any file on the desired mount. If `.f_flag & ST_RDONLY`, it is mounted read-only. – Nominal Animal Feb 07 '17 at 22:07
  • A stupid solution will be to use [`access()`](https://linux.die.net/man/2/access) – Stargateur Feb 07 '17 at 22:11
  • 1
    _Side note:_ If you look at the man page for `statvfs` [as suggested by Nominal Animal], it notes that an _older_ version of `statvfs` gathered the flags by parsing `/proc/mounts`--so you weren't too far off. The man page also notes that `statvfs` calls the linux syscall `statfs` to get this info now. – Craig Estey Feb 07 '17 at 22:14
  • 2
    Related, [Best POSIX way to determine if a filesystem is mounted read only](http://stackoverflow.com/q/4894743/608639) and [How to discover that a pendrive is in read-only mode?](http://stackoverflow.com/q/12484364/608639) – jww Feb 07 '17 at 22:17
  • @NominalAnimal I think your comment contains the answer I'm looking for; if you want to repost it as an Answer I'll mark it. – Jeremy Friesner Feb 08 '17 at 03:15
  • If you were trying to write in a file that was read-write and suddenly became read-only, the most easy way to check the filesystem has become read-only is to check the `errno` variable as it should have `EROFS` or `"Read only filesystem error"`. – Luis Colorado Feb 09 '17 at 06:34

2 Answers2

3

The getmntent() family should meet your needs.

NAME

getmntent, setmntent, addmntent, endmntent, hasmntopt, getmntent_r - get filesystem descriptor file entry

SYNOPSIS

   #include <stdio.h>
   #include <mntent.h>

   FILE *setmntent(const char *filename, const char *type);

   struct mntent *getmntent(FILE *stream);

   int addmntent(FILE *stream, const struct mntent *mnt);

   int endmntent(FILE *streamp);

   char *hasmntopt(const struct mntent *mnt, const char *opt);

   /* GNU extension */
   #include <mntent.h>

   struct mntent *getmntent_r(FILE *streamp, struct mntent *mntbuf,
                              char *buf, int buflen);

DESCRIPTION

These routines are used to access the filesystem description file /etc/fstab and the mounted filesystem description file /etc/mtab.

The setmntent() function opens the filesystem description file filename and returns a file pointer which can be used by getmntent(). The argument type is the type of access required and can take the same values as the mode argument of fopen(3).

The getmntent() function reads the next line of the filesystem description file from stream and returns a pointer to a structure containing the broken out fields from a line in the file. The pointer points to a static area of memory which is overwritten by subsequent calls to getmntent().

The addmntent() function adds the mntent structure mnt to the end of the open stream.

The endmntent() function closes the stream associated with the filesystem description file.

The hasmntopt() function scans the mnt_opts field (see below) of the mntent structure mnt for a substring that matches opt. See and mount(8) for valid mount options.

The reentrant getmntent_r() function is similar to getmntent(), but stores the struct mount in the provided *mntbuf and stores the strings pointed to by the entries in that struct in the provided array buf of size buflen.

The mntent structure is defined in as follows:

       struct mntent {
           char *mnt_fsname;   /* name of mounted filesystem */
           char *mnt_dir;      /* filesystem path prefix */
           char *mnt_type;     /* mount type (see mntent.h) */
           char *mnt_opts;     /* mount options (see mntent.h) */
           int   mnt_freq;     /* dump frequency in days */
           int   mnt_passno;   /* pass number on parallel fsck */
       };

...

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • It sounds like this would give me information about the contents of /etc/fstab, which might not necessarily be the same thing as the current state of the mounted filesystem, if the filesystem has been remounted as read-only due to a disk error(?) – Jeremy Friesner Feb 07 '17 at 22:45
  • @JeremyFriesner I don't know any easy way to programmatically determine if a filesystem has been remounted read-only because of a disk error other than trying to write to it. If that's a requirement you have to meet, you should probably test it somehow. If you're lucky, the visible mount options will changes. Or you can ask another, follow-on question - somebody out there probably knows already. – Andrew Henle Feb 07 '17 at 22:50
  • 1
    The `getmntent` family simply reads and parses the `/etc/fstab` or `/etc/mtab` (actually any file fed into when calling `setmntent`), and the paring is also very simple - it reads file line by line then splits the line into fields. Needless to say, programmer need compare the split field `mnt_fsname` against the filesystem to be verified and need parse string for "ro" mount options from `mnt_opts`. This is not a good solution while @Nominal Animal 's comment `statvfs()` or simlar is clean and better. – Yingyu YOU Apr 08 '20 at 01:25
  • To follow solution of `getmntent()` and to address the question (i.e. to check filesystem remounted as read-only), `/etc/mtab` need be fed in as it is the "mounted file system description file" according to manual page of `getmntent()`. – Yingyu YOU Apr 08 '20 at 02:12
2

The easiest way to check that the filesystem of an open file for writing has become mounted read-only is to check the errno variable for EROFS error.

If you don't have the possibility of having a writable directory or file in that filesystem, you cannot get a portable way of checking if the filesystem has become read only (more if it has become so due to device errors)

Another way is to ask the administrator to check, or try to read the /proc/mounts file yourself. But this is linux specific only.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31