Subject: df bug on 64-bit Solaris (need to use getextmntent)

From: "Wood, David" <[email-masked]>
Date: Fri, 6 Aug 2010 15:56:07 -0400

Hello,

>From mnttab(4) on Solaris 10:

     ...

     WARNINGS

     The mnttab file system provides the previously  undocumented
     dev=xxx  option  in  the option string for each mounted file
     system. This is provided for legacy applications that  might
     have been using the dev=information option.

     Using  dev=option  in  applications is strongly discouraged.
     The device number string represents a  32-bit  quantity  and
     might  not  contain  correct  information in 64-bit environ-
     ments.

     Applications requiring device number information for mounted
     file  systems  should  use  the  getextmntent(3C) interface,
     which functions properly in either 32-  or  64-bit  environ-
     ments.

Indeed, if one compiles coreutils 64-bit, the logic breaks down around line 718 of df.c:

        if (statp->st_dev == me->me_dev
            && !STREQ (me->me_type, "lofs")
            && (!best_match || best_match->me_dummy || !me->me_dummy))
          {

At this point, me->me_dev contains a wrongly packed (32-bit) device number, which forces the find_mount_point() code path (causing other unpleasantries).  The following patch against coreutils v8.5 fixes the problem:

--- mountlist.c 3 Aug 2010 21:53:14 -0000       1.1.1.4
+++ mountlist.c 6 Aug 2010 18:16:55 -0000       1.2
@@ -107,6 +107,10 @@
 # include <sys/mnttab.h>
 #endif

+#ifdef MOUNTED_GETEXTMNTENT     /* need makedev when using getextmntent */
+# include <sys/mkdev.h>
+#endif
+
 #ifdef MOUNTED_VMOUNT           /* AIX.  */
 # include <fshelp.h>
 # include <sys/vfs.h>
@@ -125,7 +129,8 @@

 #undef MNT_IGNORE
 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
-# define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
+/* cast to a mnttab struct pointer to also support extmnttab */
+# define MNT_IGNORE(M) hasmntopt ((struct mnttab *) M, MNTOPT_IGNORE)
 #else
 # define MNT_IGNORE(M) 0
 #endif
@@ -714,7 +719,11 @@

 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
   {
+# ifdef MOUNTED_GETEXTMNTENT
+    struct extmnttab mnt;
+# else
     struct mnttab mnt;
+# endif
     char *table = MNTTAB;
     FILE *fp;
     int ret;
@@ -755,7 +764,11 @@
       ret = errno;
     else
       {
+# ifdef MOUNTED_GETEXTMNTENT
+        while ((ret = getextmntent (fp, &mnt, sizeof (struct extmnttab))) == 0)
+# else
         while ((ret = getmntent (fp, &mnt)) == 0)
+# endif
           {
             me = xmalloc (sizeof *me);
             me->me_devname = xstrdup (mnt.mnt_special);
@@ -764,7 +777,11 @@
             me->me_type_malloced = 1;
             me->me_dummy = MNT_IGNORE (&mnt) != 0;
             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
+# ifdef MOUNTED_GETEXTMNTENT
+            me->me_dev = makedev(mnt.mnt_major, mnt.mnt_minor);
+# else
             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
+# endif

             /* Add to the linked list. */
             *mtail = me;