Hello everyone, I'd like to know if someone here conceived using the statfs() system call in find_root_device() (or grub_guess_root_device()) instead of doing a linear look-up into the /dev directory.
My concern here is, that on FreeBSD system using devfs or not, the approach employed by find_root_device() of getting the dev_t from struct stat st_dev is not functional. The reason is simple, the function assume that the st_dev value would be identical for an inode of a particular device and for the device entry of /dev. I wrote a short program (in attachment), that provided me the proof of what I am reporting below. FreeBSD-4.11 > ./test $HOME /dev/ad0s1f /tmp /dev/ad0s1h / /dev/ad0s1a $HOME : dev_t=160773, mntfrom="/dev/ad0s1f", mnton="/home" /dev/ad0s1f : dev_t=160768, mntfrom="/dev/ad0s1a", mnton="/" /tmp : dev_t=160775, mntfrom="/dev/ad0s1h", mnton="/tmp" /dev/ad0s1h : dev_t=160768, mntfrom="/dev/ad0s1a", mnton="/" / : dev_t=160768, mntfrom="/dev/ad0s1a", mnton="/" /dev/ad0s1a : dev_t=160768, mntfrom="/dev/ad0s1a", mnton="/" Freebsd-6.2_devfs> ./test . /dev/ad4s1h /tmp /dev/ad4s1e / /dev/ad4s1a /dev /mnt . : dev_t=117, mntfrom="/dev/ad4s1h", mnton="/home" /dev/ad4s1h : dev_t=16842496, mntfrom="devfs", mnton="/dev" /tmp : dev_t=114, mntfrom="/dev/ad4s1e", mnton="/tmp" /dev/ad4s1e : dev_t=16842496, mntfrom="devfs", mnton="/dev" / : dev_t=110, mntfrom="/dev/ad4s1a", mnton="/" /dev/ad4s1a : dev_t=16842496, mntfrom="devfs", mnton="/dev" /dev : dev_t=16842496, mntfrom="devfs", mnton="/dev" /mnt : dev_t=138, mntfrom="/dev/ad0s1a", mnton="/mnt" OpenBSD-3.2 > ./test . /dev/wd0a /mnt/cdrom/I386 /dev/cd0a . : dev_t=0, mntfrom="/dev/wd0a", mnton="/" /dev/wd0a : dev_t=0, mntfrom="/dev/wd0a", mnton="/" /mnt/cdrom/I386 : dev_t=768, mntfrom="/dev/cd0a", mnton="/mnt/cdrom" /dev/cd0a : dev_t=0, mntfrom="/dev/wd0a", mnton="/" Speculating, it seems there is a difference between 44BSD (?) and Linux in the assigned value of st_dev. While Linux seems to set the same value for the inodes on the device and the device entry in /dev, BSDs tends to treat entries in /dev as inodes of the device there are stored on. My recommendation would be relatively simple. grub_guess_root_device() could simply call statfs() and extract the device name from struct statfs f_mntfromname, maybe as simply as the following, but I may lack of knowledge about some technologies on which this might not work (like RAID ...). size_t strnlen (const char *s, size_t max) { size_t l = 0; if ( s ) for (; l < max && *s ; ++l ); return l; } char * grub_guess_root_device (const char *path) { char *ret = NULL; struct statfs sfsb; if ( statfs (path, &sfsb) ) { ret = xmalloc (strnlen (sfsb.f_mntfromname, MNAMELEN)); if ( ret ) strncpy (ret, sfsb.f_mntfromname, MNAMELEN); else { perror ("Root device string allocation failed!"); exit (ENOMEM); } } else { grub_util_error ("unable to stat `%s'", path); } return ret; } I would like to know what you guys think about this. Francis Gendreau
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/param.h> #include <sys/mount.h> void do_stat( const char *path); int main( int argc, char **argv) { int i; if ( argc > 1 ) for ( i = 1; i < argc; ++i) do_stat( argv[i]); else printf( "usage: %s <path> [<path> ...]\n", argv[0]); return 0; } void do_stat( const char *path) { struct stat sb; struct statfs sfsb; if ( !stat( path, &sb) ) { if ( !statfs( path, &sfsb) ) { printf( "%s: dev_t=%d, mntfrom=\"%s\", mnton=\"%s\"\n", path, sb.st_dev, sfsb.f_mntfromname, sfsb.f_mntonname ); return; } printf( "cannot statfs() %s\n", path); // should never print } printf( "cannot stat() %s\n", path); }
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel