diff --git a/doc/Changelog b/doc/Changelog index aa67744..631c199 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,11 @@ sysvinit (2.89) UNRELEASED; urgency=low [ Jesse Smith ] + * Updated mountpoint command with -p flag. The -p flag causes + mountpoint to search for circular mount points. For example, if + /a/b/c/d is a mount point for /a/b then the former is a valid + mount point. This only works on Linux since it uses /proc/mounts. + Updated manual page to match. This fix closes Savannah bug #37114. * Removed two sleep calls when we are doing sync anyway to make sure data is being written. Speeds up reboot time by about two seconds. * Fixed Clang compiler warning regarding variable data parameters to sprintf(). diff --git a/man/mountpoint.1 b/man/mountpoint.1 index e873e78..992c9f5 100644 --- a/man/mountpoint.1 +++ b/man/mountpoint.1 @@ -35,6 +35,8 @@ mountpoint \- see if a directory is a mountpoint Be quiet - don't print anything. .IP \fB\-d\fP Print major/minor device number of the filesystem on stdout. +.IP \fB\-p\fP +Check Linux's /proc/mounts file to try to detect circular mount points. .IP \fB\-x\fP Print major/minor device number of the blockdevice on stdout. .SH EXIT STATUS @@ -48,6 +50,19 @@ The name of the command is misleading when the -x option is used, but the option is useful for comparing if a directory and a device match up, and there is no other command that can print the info easily. .PP +The mountpoint command fails when a directory is binded to one of its grandparents. +For example, if /a/b/c/d is a mount point for /a/b then mountpoint will report +/a/b/c/d is not a valid mount point. This is because both the original directory and +its new mount point share the same inode and device number. +.PP +The circular mount problem can be worked around on Linux systems by using +the -p flag to check the /proc/mounts file for references to the circular mount bind. +When using the -p flag, make sure to specify the full path (ie /home/user/mp and +not just mp). Also, mountpoint may still fail if there are spaces in +the mount point's path, even when using the -p flag because of the way +/proc/mounts mangles the spaces in the path name. Of course, if the +admin is using circular mount points with spaces in the name, there +are bigger concerns. .SH AUTHOR Miquel van Smoorenburg, miquels@cistron.nl .SH "SEE ALSO" diff --git a/src/mountpoint.c b/src/mountpoint.c index aca6c04..5cdffec 100644 --- a/src/mountpoint.c +++ b/src/mountpoint.c @@ -50,8 +50,55 @@ int dostat(char *path, struct stat *st, int do_lstat, int quiet) return 0; } + +/* +This function checks to see if the passed path is listed in the +/proc/mounts file. If /proc/mounts does not exist or cannot +be read, we return false. If the path is nout found, we return false. +If the path is found we return true. +*/ +int do_proc_check(char *path) +{ + FILE *mounts; + char *found = NULL, *status; + char *target_string; + char line[512]; + int last_character; + + target_string = (char *) calloc( strlen(path) + 3, sizeof(char)); + if (! target_string) + return 0; + + mounts = fopen("/proc/mounts", "r"); + if (! mounts) + { + free(target_string); + return 0; + } + + /* copy path so we can adjust it without harming the original */ + sprintf(target_string, "%s", path); + /* trim trailing slash */ + last_character = strlen(target_string) - 1; + if ( (last_character >= 1) && (target_string[last_character] == '/') ) + target_string[last_character] = '\0'; + + /* Search for path name in /proc/mounts file */ + status = fgets(line, 512, mounts); + while ( (status) && (! found) ) + { + found = strstr(line, target_string); + if (! found) + status = fgets(line, 512, mounts); + } + fclose(mounts); + free(target_string); + return found ? 1 : 0; +} + + void usage(void) { - fprintf(stderr, "Usage: mountpoint [-q] [-d] [-x] path\n"); + fprintf(stderr, "Usage: mountpoint [-p] [-q] [-d] [-x] path\n"); exit(1); } @@ -64,11 +111,15 @@ int main(int argc, char **argv) int showdev = 0; int xdev = 0; int c, r; + int check_proc = 0; - while ((c = getopt(argc, argv, "dqx")) != EOF) switch(c) { + while ((c = getopt(argc, argv, "dpqx")) != EOF) switch(c) { case 'd': showdev = 1; break; + case 'p': + check_proc = 1; + break; case 'q': quiet = 1; break; @@ -118,6 +169,13 @@ int main(int argc, char **argv) r = (st.st_dev != st2.st_dev) || (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino); + /* Mount point was not found yet. If we have access + to /proc we can check there too. */ + if ( (!r) && (check_proc) ) + { + if ( do_proc_check(path) ) + r = 1; + } if (!quiet && !showdev) printf("%s is %sa mountpoint\n", path, r ? "" : "not ");