2 Return a list of mounted file systems
4 Copyright (C) 1991-2024
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * \brief Source: list of mounted filesystems
33 #include <stdint.h> /* SIZE_MAX */
34 #include <sys/types.h>
38 /* This header needs to be included before sys/mount.h on *BSD */
39 #ifdef HAVE_SYS_PARAM_H
40 #include <sys/param.h>
43 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
44 #include <sys/statvfs.h>
46 /* Don't include backward-compatibility files unless they're needed.
47 Eventually we'd like to remove all this cruft. */
52 #ifdef MOUNTED_GETFSSTAT /* OSF_1, also (obsolete) Apple Darwin 1.3 */
53 #ifdef HAVE_SYS_UCRED_H
54 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
55 NGROUPS is used as an array dimension in ucred.h */
56 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
58 #ifdef HAVE_SYS_MOUNT_H
59 #include <sys/mount.h>
61 #ifdef HAVE_SYS_FS_TYPES_H
62 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
64 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65 #define FS_TYPE(Ent) ((Ent).f_fstypename)
67 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
69 #endif /* MOUNTED_GETFSSTAT */
70 #endif /* STAT_STATVFS || STAT_STATVFS64 */
75 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
76 #include <sys/fs/s5param.h>
78 #ifdef HAVE_SYS_STATFS_H
79 #include <sys/statfs.h>
82 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
83 also (obsolete) 4.3BSD, SunOS */
85 #include <sys/types.h>
86 #if defined __ANDROID__ /* Android */
87 /* Bionic versions from between 2014-01-09 and 2015-01-08 define MOUNTED to
88 an incorrect value; older Bionic versions don't define it at all. */
90 #define MOUNTED "/proc/mounts"
91 #elif !defined MOUNTED
92 #ifdef _PATH_MOUNTED /* GNU libc */
93 #define MOUNTED _PATH_MOUNTED
95 #ifdef MNT_MNTTAB /* HP-UX. */
96 #define MOUNTED MNT_MNTTAB
101 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
102 #include <sys/mount.h>
105 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
106 #include <sys/statvfs.h>
109 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
114 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
116 #include <sys/fstyp.h>
117 #include <sys/statfs.h>
120 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
121 #include <sys/mnttab.h>
124 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
125 #include <sys/mnttab.h>
128 #ifdef MOUNTED_VMOUNT /* AIX */
133 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
134 #include <sys/statvfs.h>
138 #ifdef HAVE_SYS_MNTENT_H
139 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
140 #include <sys/mntent.h>
143 #ifdef MOUNTED_GETMNTENT1
144 #if !HAVE_SETMNTENT /* Android <= 4.4 */
145 #define setmntent(fp,mode) fopen (fp, mode)
147 #if !HAVE_ENDMNTENT /* Android <= 4.4 */
148 #define endmntent(fp) fclose (fp)
152 #ifndef HAVE_HASMNTOPT
153 #define hasmntopt(mnt, opt) ((char *) 0)
158 #if defined __sun && defined __SVR4
159 /* Solaris defines hasmntopt(struct mnttab *, char *)
160 while it is otherwise hasmntopt(struct mnttab *, const char *). */
161 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
163 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
166 #define MNT_IGNORE(M) 0
169 #ifdef HAVE_INFOMOUNT_QNX
170 #include <sys/disk.h>
171 #include <sys/fsys.h>
174 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
175 #include <sys/statvfs.h>
178 #include "lib/global.h"
179 #include "lib/strutil.h" /* str_verscmp() */
180 #include "lib/unixcompat.h" /* makedev */
181 #include "mountlist.h"
183 /*** global variables ****************************************************************************/
185 /*** file scope macro definitions ****************************************************************/
187 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
188 #define HAVE_INFOMOUNT_QNX
191 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
192 #define HAVE_INFOMOUNT
195 /* The results of opendir() in this file are not used with dirfd and fchdir,
196 therefore save some unnecessary work in fchdir.c. */
200 #define ME_DUMMY_0(Fs_name, Fs_type) \
201 (strcmp (Fs_type, "autofs") == 0 \
202 || strcmp (Fs_type, "proc") == 0 \
203 || strcmp (Fs_type, "subfs") == 0 \
204 /* for Linux 2.6/3.x */ \
205 || strcmp (Fs_type, "debugfs") == 0 \
206 || strcmp (Fs_type, "devpts") == 0 \
207 || strcmp (Fs_type, "fusectl") == 0 \
208 || strcmp (Fs_type, "fuse.portal") == 0 \
209 || strcmp (Fs_type, "mqueue") == 0 \
210 || strcmp (Fs_type, "rpc_pipefs") == 0 \
211 || strcmp (Fs_type, "sysfs") == 0 \
212 /* FreeBSD, Linux 2.4 */ \
213 || strcmp (Fs_type, "devfs") == 0 \
214 /* for NetBSD 3.0 */ \
215 || strcmp (Fs_type, "kernfs") == 0 \
217 || strcmp (Fs_type, "ignore") == 0)
219 /* Historically, we have marked as "dummy" any file system of type "none",
220 but now that programs like du need to know about bind-mounted directories,
221 we grant an exception to any with "bind" in its list of mount options.
222 I.e., those are *not* dummy entries. */
223 #ifdef MOUNTED_GETMNTENT1
224 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
225 (ME_DUMMY_0 (Fs_name, Fs_type) \
226 || (strcmp (Fs_type, "none") == 0 && !Bind))
228 #define ME_DUMMY(Fs_name, Fs_type) \
229 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
234 #define ME_REMOTE me_remote
235 /* All cygwin mount points include ':' or start with '//'; so it
236 requires a native Windows call to determine remote disks. */
238 me_remote (char const *fs_name
, char const *fs_type
)
242 if (fs_name
[0] && fs_name
[1] == ':')
245 sprintf (drive
, "%c:\\", fs_name
[0]);
246 switch (GetDriveType (drive
))
248 case DRIVE_REMOVABLE
:
259 /* A file system is 'remote' if its Fs_name contains a ':'
260 or if (it is of type (smbfs or smb3 or cifs) and its Fs_name starts with '//')
261 or if it is of any other of the listed types
262 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs).
263 "VM" file systems like prl_fs or vboxsf are not considered remote here. */
264 #define ME_REMOTE(Fs_name, Fs_type) \
265 (strchr (Fs_name, ':') != NULL \
266 || ((Fs_name)[0] == '/' \
267 && (Fs_name)[1] == '/' \
268 && (strcmp (Fs_type, "smbfs") == 0 \
269 || strcmp (Fs_type, "smb3") == 0 \
270 || strcmp (Fs_type, "cifs") == 0)) \
271 || strcmp (Fs_type, "acfs") == 0 \
272 || strcmp (Fs_type, "afs") == 0 \
273 || strcmp (Fs_type, "coda") == 0 \
274 || strcmp (Fs_type, "auristorfs") == 0 \
275 || strcmp (Fs_type, "fhgfs") == 0 \
276 || strcmp (Fs_type, "gpfs") == 0 \
277 || strcmp (Fs_type, "ibrix") == 0 \
278 || strcmp (Fs_type, "ocfs2") == 0 \
279 || strcmp (Fs_type, "vxfs") == 0 \
280 || strcmp ("-hosts", Fs_name) == 0)
283 /* Many space usage primitives use all 1 bits to denote a value that is
284 not applicable or unknown. Propagate this information by returning
285 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
286 is unsigned and narrower than uintmax_t. */
287 #define PROPAGATE_ALL_ONES(x) \
288 ((sizeof (x) < sizeof (uintmax_t) \
289 && (~ (x) == (sizeof (x) < sizeof (int) \
290 ? - (1 << (sizeof (x) * CHAR_BIT)) \
292 ? UINTMAX_MAX : (uintmax_t) (x))
294 /* Extract the top bit of X as an uintmax_t value. */
295 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
297 /* If a value is negative, many space usage primitives store it into an
298 integer variable by assignment, even if the variable's type is unsigned.
299 So, if a space usage variable X's top bit is set, convert X to the
300 uintmax_t value V such that (- (uintmax_t) V) is the negative of
301 the original value. If X's top bit is clear, just yield X.
302 Use PROPAGATE_TOP_BIT if the original value might be negative;
303 otherwise, use PROPAGATE_ALL_ONES. */
304 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
307 #if ! (defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__))
308 /* The FRSIZE fallback is not required in this case. */
309 #undef STAT_STATFS2_FRSIZE
311 #include <sys/utsname.h>
312 #include <sys/statfs.h>
313 #define STAT_STATFS2_BSIZE 1
317 /*** file scope type declarations ****************************************************************/
319 /* A mount table entry. */
322 char *me_devname
; /* Device node name, including "/dev/". */
323 char *me_mountdir
; /* Mount point directory name. */
324 char *me_mntroot
; /* Directory on filesystem of device used
325 as root for the (bind) mount. */
326 char *me_type
; /* "nfs", "4.2", etc. */
327 dev_t me_dev
; /* Device number of me_mountdir. */
328 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
329 unsigned int me_remote
:1; /* Nonzero for remote filesystems. */
330 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
335 uintmax_t fsu_blocksize
; /* Size of a block. */
336 uintmax_t fsu_blocks
; /* Total blocks. */
337 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
338 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
339 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
340 uintmax_t fsu_files
; /* Total file nodes. */
341 uintmax_t fsu_ffree
; /* Free file nodes. */
344 /*** forward declarations (file scope functions) *************************************************/
346 /*** file scope variables ************************************************************************/
348 #ifdef HAVE_INFOMOUNT_LIST
349 static GSList
*mc_mount_list
= NULL
;
350 #endif /* HAVE_INFOMOUNT_LIST */
352 /* --------------------------------------------------------------------------------------------- */
353 /*** file scope functions ************************************************************************/
354 /* --------------------------------------------------------------------------------------------- */
357 /* Return true if statvfs works. This is false for statvfs on systems
358 with GNU libc on Linux kernels before 2.6.36, which stats all
359 preceding entries in /proc/mounts; that makes df hang if even one
360 of the corresponding file systems is hard-mounted but not available. */
364 #if ! (defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__))
367 static int statvfs_works_cache
= -1;
370 if (statvfs_works_cache
< 0)
371 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= str_verscmp (name
.release
, "2.6.36"));
372 return statvfs_works_cache
;
377 /* --------------------------------------------------------------------------------------------- */
379 #ifdef HAVE_INFOMOUNT_LIST
381 free_mount_entry (struct mount_entry
*me
)
385 g_free (me
->me_devname
);
386 g_free (me
->me_mountdir
);
387 g_free (me
->me_mntroot
);
388 if (me
->me_type_malloced
)
389 g_free (me
->me_type
);
393 /* --------------------------------------------------------------------------------------------- */
395 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
397 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
399 fstype_to_string (short int t
)
404 /* cppcheck-suppress syntaxError */
409 /* cppcheck-suppress syntaxError */
414 /* cppcheck-suppress syntaxError */
419 /* cppcheck-suppress syntaxError */
424 /* cppcheck-suppress syntaxError */
429 /* cppcheck-suppress syntaxError */
434 /* cppcheck-suppress syntaxError */
439 /* cppcheck-suppress syntaxError */
444 /* cppcheck-suppress syntaxError */
449 /* cppcheck-suppress syntaxError */
454 /* cppcheck-suppress syntaxError */
459 /* cppcheck-suppress syntaxError */
464 /* cppcheck-suppress syntaxError */
469 /* cppcheck-suppress syntaxError */
474 /* cppcheck-suppress syntaxError */
479 /* cppcheck-suppress syntaxError */
484 /* cppcheck-suppress syntaxError */
489 /* cppcheck-suppress syntaxError */
494 /* cppcheck-suppress syntaxError */
499 /* cppcheck-suppress syntaxError */
504 /* cppcheck-suppress syntaxError */
512 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
514 /* --------------------------------------------------------------------------------------------- */
517 fsp_to_string (const struct statfs
*fsp
)
519 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
520 return (char *) (fsp
->f_fstypename
);
522 return fstype_to_string (fsp
->f_type
);
525 #endif /* MOUNTED_GETMNTINFO */
527 /* --------------------------------------------------------------------------------------------- */
529 #ifdef MOUNTED_VMOUNT /* AIX */
531 fstype_to_string (int t
)
535 e
= getvfsbytype (t
);
536 if (!e
|| !e
->vfsent_name
)
539 return e
->vfsent_name
;
541 #endif /* MOUNTED_VMOUNT */
543 /* --------------------------------------------------------------------------------------------- */
545 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
547 /* Return the device number from MOUNT_OPTIONS, if possible.
548 Otherwise return (dev_t) -1. */
550 /* --------------------------------------------------------------------------------------------- */
553 dev_from_mount_options (char const *mount_options
)
555 /* GNU/Linux allows file system implementations to define their own
556 meaning for "dev=" mount options, so don't trust the meaning
559 static char const dev_pattern
[] = ",dev=";
560 char const *devopt
= strstr (mount_options
, dev_pattern
);
564 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
566 unsigned long int dev
;
568 dev
= strtoul (optval
, &optvalend
, 16);
569 if (optval
!= optvalend
570 && (*optvalend
== '\0' || *optvalend
== ',')
571 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
576 (void) mount_options
;
582 /* --------------------------------------------------------------------------------------------- */
584 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
586 /* Unescape the paths in mount tables.
587 STR is updated in place. */
589 unescape_tab (char *str
)
594 len
= strlen (str
) + 1;
596 for (i
= 0; i
< len
; i
++)
598 if (str
[i
] == '\\' && (i
+ 4 < len
)
599 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
600 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7' && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
602 str
[j
++] = (str
[i
+ 1] - '0') * 64 + (str
[i
+ 2] - '0') * 8 + (str
[i
+ 3] - '0');
611 /* --------------------------------------------------------------------------------------------- */
613 /* Return a list of the currently mounted file systems, or NULL on error.
614 Add each entry to the tail of the list so that they stay in order. */
617 read_file_system_list (void)
619 GSList
*mount_list
= NULL
;
620 struct mount_entry
*me
;
622 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
623 also (obsolete) 4.3BSD, SunOS */
627 #if defined __linux__ || defined __ANDROID__
628 /* Try parsing mountinfo first, as that make device IDs available.
629 Note we could use libmount routines to simplify this parsing a little
630 (and that code is in previous versions of this function), however
631 libmount depends on libselinux which pulls in many dependencies. */
632 char const *mountinfo
= "/proc/self/mountinfo";
634 fp
= fopen (mountinfo
, "r");
640 while (getline (&line
, &buf_size
, fp
) != -1)
642 unsigned int devmaj
, devmin
;
643 int target_s
, target_e
, type_s
, type_e
;
644 int source_s
, source_e
, mntroot_s
, mntroot_e
;
649 rc
= sscanf (line
, "%*u " /* id - discarded */
650 "%*u " /* parent - discarded */
651 "%u:%u " /* dev major:minor */
652 "%n%*s%n " /* mountroot */
653 "%n%*s%n" /* target, start and end */
654 "%c", /* more data... */
655 &devmaj
, &devmin
, &mntroot_s
, &mntroot_e
, &target_s
, &target_e
, &test
);
657 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
660 /* skip optional fields, terminated by " - " */
661 dash
= strstr (line
+ target_e
, " - ");
665 rc
= sscanf (dash
, " - " /* */
666 "%n%*s%n " /* FS type, start and end */
667 "%n%*s%n " /* source, start and end */
668 "%c", /* more data... */
669 &type_s
, &type_e
, &source_s
, &source_e
, &test
);
670 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
673 /* manipulate the sub-strings in place. */
674 line
[mntroot_e
] = '\0';
675 line
[target_e
] = '\0';
677 dash
[source_e
] = '\0';
678 unescape_tab (dash
+ source_s
);
679 unescape_tab (line
+ target_s
);
680 unescape_tab (line
+ mntroot_s
);
682 me
= g_malloc (sizeof *me
);
684 me
->me_devname
= g_strdup (dash
+ source_s
);
685 me
->me_mountdir
= g_strdup (line
+ target_s
);
686 me
->me_mntroot
= g_strdup (line
+ mntroot_s
);
687 me
->me_type
= g_strdup (dash
+ type_s
);
688 me
->me_type_malloced
= 1;
689 me
->me_dev
= makedev (devmaj
, devmin
);
690 /* we pass "false" for the "Bind" option as that's only
691 significant when the Fs_type is "none" which will not be
692 the case when parsing "/proc/self/mountinfo", and only
693 applies for static /etc/mtab files. */
694 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, FALSE
);
695 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
697 mount_list
= g_slist_prepend (mount_list
, me
);
702 if (ferror (fp
) != 0)
704 int saved_errno
= errno
;
711 if (fclose (fp
) == EOF
)
714 else /* fallback to /proc/self/mounts (/etc/mtab). */
715 #endif /* __linux __ || __ANDROID__ */
718 const char *table
= MOUNTED
;
720 fp
= setmntent (table
, "r");
724 while ((mnt
= getmntent (fp
)) != NULL
)
728 bind
= hasmntopt (mnt
, "bind") != NULL
;
730 me
= g_malloc (sizeof (*me
));
731 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
732 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
733 me
->me_mntroot
= NULL
;
734 me
->me_type
= g_strdup (mnt
->mnt_type
);
735 me
->me_type_malloced
= 1;
736 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
737 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
738 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
740 mount_list
= g_slist_prepend (mount_list
, me
);
743 if (endmntent (fp
) == 0)
747 #endif /* MOUNTED_GETMNTENT1. */
749 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
754 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
757 for (; entries
-- > 0; fsp
++)
759 char *fs_type
= fsp_to_string (fsp
);
761 me
= g_malloc (sizeof (*me
));
762 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
763 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
764 me
->me_mntroot
= NULL
;
765 me
->me_type
= fs_type
;
766 me
->me_type_malloced
= 0;
767 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
768 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
769 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
771 mount_list
= g_slist_prepend (mount_list
, me
);
774 #endif /* MOUNTED_GETMNTINFO */
776 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
781 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
784 for (; entries
-- > 0; fsp
++)
786 me
= g_malloc (sizeof (*me
));
787 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
788 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
789 me
->me_mntroot
= NULL
;
790 me
->me_type
= g_strdup (fsp
->f_fstypename
);
791 me
->me_type_malloced
= 1;
792 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
793 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
794 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
796 mount_list
= g_slist_prepend (mount_list
, me
);
799 #endif /* MOUNTED_GETMNTINFO2 */
801 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
803 /* The next_dev() and fs_stat_dev() system calls give the list of
804 all file systems, including the information returned by statvfs()
805 (fs type, total blocks, free blocks etc.), but without the mount
806 point. But on BeOS all file systems except / are mounted in the
807 rootfs, directly under /.
808 The directory name of the mount point is often, but not always,
809 identical to the volume name of the device.
810 We therefore get the list of subdirectories of /, and the list
811 of all file systems, and match the two lists. */
819 struct rootdir_entry
*next
;
821 struct rootdir_entry
*rootdir_list
;
822 struct rootdir_entry
**rootdir_tail
;
827 /* All volumes are mounted in the rootfs, directly under /. */
829 rootdir_tail
= &rootdir_list
;
830 dirp
= opendir (PATH_SEP_STR
);
835 while ((d
= readdir (dirp
)) != NULL
)
840 if (DIR_IS_DOT (d
->d_name
))
843 if (DIR_IS_DOTDOT (d
->d_name
))
844 name
= g_strdup (PATH_SEP_STR
);
846 name
= g_strconcat (PATH_SEP_STR
, d
->d_name
, (char *) NULL
);
848 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
850 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
852 re
->dev
= statbuf
.st_dev
;
853 re
->ino
= statbuf
.st_ino
;
855 /* Add to the linked list. */
857 rootdir_tail
= &re
->next
;
864 *rootdir_tail
= NULL
;
866 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
867 if (fs_stat_dev (dev
, &fi
) >= 0)
869 /* Note: fi.dev == dev. */
870 struct rootdir_entry
*re
;
872 for (re
= rootdir_list
; re
; re
= re
->next
)
873 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
876 me
= g_malloc (sizeof (*me
));
878 g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
879 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
880 me
->me_mntroot
= NULL
;
881 me
->me_type
= g_strdup (fi
.fsh_name
);
882 me
->me_type_malloced
= 1;
885 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
887 mount_list
= g_slist_prepend (mount_list
, me
);
890 while (rootdir_list
!= NULL
)
892 struct rootdir_entry
*re
= rootdir_list
;
894 rootdir_list
= re
->next
;
899 #endif /* MOUNTED_FS_STAT_DEV */
901 #ifdef MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
905 struct statfs
*stats
;
907 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
910 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
912 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
916 bufsize
= (1 + numsys
) * sizeof (*stats
);
917 stats
= g_malloc (bufsize
);
918 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
926 for (counter
= 0; counter
< numsys
; counter
++)
928 me
= g_malloc (sizeof (*me
));
929 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
930 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
931 me
->me_mntroot
= NULL
;
932 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
933 me
->me_type_malloced
= 1;
934 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
935 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
936 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
938 mount_list
= g_slist_prepend (mount_list
, me
);
943 #endif /* MOUNTED_GETFSSTAT */
945 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
948 char *table
= "/etc/mnttab";
951 fp
= fopen (table
, "r");
955 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
957 me
= g_malloc (sizeof (*me
));
958 me
->me_devname
= g_strdup (mnt
.mt_dev
);
959 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
960 me
->me_mntroot
= NULL
;
961 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
963 me
->me_type_malloced
= 0;
966 char typebuf
[FSTYPSZ
];
968 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
969 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
971 me
->me_type
= g_strdup (typebuf
);
972 me
->me_type_malloced
= 1;
975 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
976 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
978 mount_list
= g_slist_prepend (mount_list
, me
);
983 /* The last fread() call must have failed. */
984 int saved_errno
= errno
;
991 if (fclose (fp
) == EOF
)
994 #endif /* MOUNTED_FREAD_FSTYP */
996 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
998 struct extmnttab mnt
;
999 const char *table
= MNTTAB
;
1003 /* No locking is needed, because the contents of /etc/mnttab is generated by the kernel. */
1006 fp
= fopen (table
, "r");
1011 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
1013 me
= g_malloc (sizeof *me
);
1014 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1015 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1016 me
->me_mntroot
= NULL
;
1017 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1018 me
->me_type_malloced
= 1;
1019 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1020 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1021 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
1023 mount_list
= g_slist_prepend (mount_list
, me
);
1026 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1027 /* Here ret = -1 means success, ret >= 0 means failure. */
1033 goto free_then_fail
;
1036 #endif /* MOUNTED_GETEXTMNTENT */
1038 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
1041 const char *table
= MNTTAB
;
1046 #if defined F_RDLCK && defined F_SETLKW
1047 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
1048 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
1049 for this file name, we should use their macro name instead.
1050 (Why not just lock MNTTAB directly? We don't know.) */
1052 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1054 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
1059 flock
.l_type
= F_RDLCK
;
1060 flock
.l_whence
= SEEK_SET
;
1063 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
1066 int saved_errno
= errno
;
1068 errno
= saved_errno
;
1072 else if (errno
!= ENOENT
)
1077 fp
= fopen (table
, "r");
1082 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1084 me
= g_malloc (sizeof (*me
));
1085 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1086 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1087 me
->me_mntroot
= NULL
;
1088 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1089 me
->me_type_malloced
= 1;
1090 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1091 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1092 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1094 mount_list
= g_slist_prepend (mount_list
, me
);
1097 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1098 /* Here ret = -1 means success, ret >= 0 means failure. */
1101 if (lockfd
>= 0 && close (lockfd
) != 0)
1107 goto free_then_fail
;
1110 #endif /* MOUNTED_GETMNTENT2. */
1112 #ifdef MOUNTED_VMOUNT /* AIX */
1121 /* Ask how many bytes to allocate for the mounted file system info. */
1123 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), entries
) != 0)
1125 entries
= g_malloc (bufsize
);
1127 /* Get the list of mounted file systems. */
1128 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1131 int saved_errno
= errno
;
1134 errno
= saved_errno
;
1138 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1140 char *options
, *ignore
;
1142 vmp
= (struct vmount
*) thisent
;
1143 me
= g_malloc (sizeof (*me
));
1144 if (vmp
->vmt_flags
& MNT_REMOTE
)
1149 /* Prepend the remote dirname. */
1150 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1151 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1152 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1157 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1159 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1160 me
->me_mntroot
= NULL
;
1161 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1162 me
->me_type_malloced
= 1;
1163 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1164 ignore
= strstr (options
, "ignore");
1165 me
->me_dummy
= (ignore
1166 && (ignore
== options
|| ignore
[-1] == ',')
1167 && (ignore
[sizeof ("ignore") - 1] == ','
1168 || ignore
[sizeof ("ignore") - 1] == '\0'));
1169 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1171 mount_list
= g_slist_prepend (mount_list
, me
);
1175 #endif /* MOUNTED_VMOUNT. */
1177 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1179 DIR *dirp
= opendir ("/dev/fs");
1180 char node
[9 + NAME_MAX
];
1183 goto free_then_fail
;
1188 struct dirent entry
;
1189 struct dirent
*result
;
1191 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1194 strcpy (node
, "/dev/fs/");
1195 strcat (node
, entry
.d_name
);
1197 if (statvfs (node
, &dev
) == 0)
1199 me
= g_malloc (sizeof *me
);
1200 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1201 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1202 me
->me_mntroot
= NULL
;
1203 me
->me_type
= g_strdup (dev
.f_fstypename
);
1204 me
->me_type_malloced
= 1;
1205 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1206 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1207 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1209 mount_list
= g_slist_prepend (mount_list
, me
);
1214 #endif /* MOUNTED_INTERIX_STATVFS */
1216 return g_slist_reverse (mount_list
);
1220 int saved_errno
= errno
;
1222 g_slist_free_full (mount_list
, (GDestroyNotify
) free_mount_entry
);
1224 errno
= saved_errno
;
1228 #endif /* HAVE_INFOMOUNT_LIST */
1230 /* --------------------------------------------------------------------------------------------- */
1232 #ifdef HAVE_INFOMOUNT_QNX
1234 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1235 ** this via the following code.
1236 ** Note that, as this is based on CWD, it only fills one mount_entry
1237 ** structure. See my_statfs() below for the "other side" of this hack.
1241 read_file_system_list (void)
1243 struct _disk_entry de
;
1246 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1247 struct mount_entry
*me
= NULL
;
1248 static GSList
*list
= NULL
;
1252 me
= (struct mount_entry
*) list
->data
;
1254 g_free (me
->me_devname
);
1255 g_free (me
->me_mountdir
);
1256 g_free (me
->me_mntroot
);
1257 g_free (me
->me_type
);
1261 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1262 list
= g_slist_prepend (list
, me
);
1265 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1268 fd
= open (dir
, O_RDONLY
);
1272 i
= disk_get_entry (fd
, &de
);
1279 switch (de
.disk_type
)
1306 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1309 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1312 me
->me_devname
= g_strdup (dev
);
1313 me
->me_mountdir
= g_strdup (dir
);
1314 me
->me_mntroot
= NULL
;
1315 me
->me_type
= g_strdup (tp
);
1316 me
->me_dev
= de
.disk_type
;
1320 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1321 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1322 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1323 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1328 #endif /* HAVE_INFOMOUNT_QNX */
1330 /* --------------------------------------------------------------------------------------------- */
1332 #ifdef HAVE_INFOMOUNT
1333 /* Fill in the fields of FSP with information about space usage for
1334 the file system on which FILE resides.
1335 DISK is the device on which FILE is mounted, for space-getting
1336 methods that need to know it.
1337 Return 0 if successful, -1 if not. When returning -1, ensure that
1338 ERRNO is either a system error value, or zero if DISK is NULL
1339 on a system that requires a non-NULL value. */
1341 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1343 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1345 if (statvfs_works ())
1347 struct statvfs vfsd
;
1349 if (statvfs (file
, &vfsd
) < 0)
1352 /* f_frsize isn't guaranteed to be supported. */
1353 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1354 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1355 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1357 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1358 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1359 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1360 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1361 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1362 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1368 #if defined STAT_STATVFS64 /* AIX */
1370 struct statvfs64 fsd
;
1372 if (statvfs64 (file
, &fsd
) < 0)
1375 /* f_frsize isn't guaranteed to be supported. */
1377 fsp
->fsu_blocksize
= fsd
.f_frsize
1378 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1379 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1382 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1386 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1389 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1391 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1395 if (statfs (file
, &fsd
) < 0)
1398 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1400 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1401 Mac OS X < 10.4, FreeBSD < 5.0, \
1402 NetBSD < 3.0, OpenBSD < 4.4 */
1406 if (statfs (file
, &fsd
) < 0)
1409 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1411 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1413 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1414 struct statfs are truncated to 2GB. These conditions detect that
1415 truncation, presumably without botching the 4.1.1 case, in which
1416 the values are not truncated. The correct counts are stored in
1417 undocumented spare fields. */
1418 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1420 fsd
.f_blocks
= fsd
.f_spare
[0];
1421 fsd
.f_bfree
= fsd
.f_spare
[1];
1422 fsd
.f_bavail
= fsd
.f_spare
[2];
1424 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1426 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1430 if (statfs (file
, &fsd
) < 0)
1433 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1435 #elif defined STAT_STATFS4 /* SVR3, old Irix */
1439 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1442 /* Empirically, the block counts on most SVR3 and SVR3-derived
1443 systems seem to always be in terms of 512-byte blocks,
1444 no matter what value f_bsize has. */
1445 fsp
->fsu_blocksize
= 512;
1448 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1449 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1450 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1452 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1453 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1454 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1455 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1456 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1457 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1462 (void) disk
; /* avoid argument-unused warning */
1466 #endif /* HAVE_INFOMOUNT */
1468 /* --------------------------------------------------------------------------------------------- */
1469 /*** public functions ****************************************************************************/
1470 /* --------------------------------------------------------------------------------------------- */
1473 free_my_statfs (void)
1475 #ifdef HAVE_INFOMOUNT_LIST
1476 g_clear_slist (&mc_mount_list
, (GDestroyNotify
) free_mount_entry
);
1477 #endif /* HAVE_INFOMOUNT_LIST */
1480 /* --------------------------------------------------------------------------------------------- */
1483 init_my_statfs (void)
1485 #ifdef HAVE_INFOMOUNT_LIST
1487 mc_mount_list
= read_file_system_list ();
1488 #endif /* HAVE_INFOMOUNT_LIST */
1491 /* --------------------------------------------------------------------------------------------- */
1494 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1496 #ifdef HAVE_INFOMOUNT_LIST
1498 struct mount_entry
*entry
= NULL
;
1500 struct fs_usage fs_use
;
1502 for (temp
= mc_mount_list
; temp
!= NULL
; temp
= g_slist_next (temp
))
1504 struct mount_entry
*me
;
1507 me
= (struct mount_entry
*) temp
->data
;
1508 i
= strlen (me
->me_mountdir
);
1509 if (i
> len
&& (strncmp (path
, me
->me_mountdir
, i
) == 0) &&
1510 (entry
== NULL
|| IS_PATH_SEP (path
[i
]) || path
[i
] == '\0'))
1519 memset (&fs_use
, 0, sizeof (fs_use
));
1520 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1522 myfs_stats
->type
= entry
->me_dev
;
1523 myfs_stats
->typename
= entry
->me_type
;
1524 myfs_stats
->mpoint
= entry
->me_mountdir
;
1525 myfs_stats
->mroot
= entry
->me_mntroot
;
1526 myfs_stats
->device
= entry
->me_devname
;
1528 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1529 fs_use
.fsu_blocksize
) >> 10;
1530 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1531 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1532 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1535 #endif /* HAVE_INFOMOUNT_LIST */
1537 #ifdef HAVE_INFOMOUNT_QNX
1539 ** This is the "other side" of the hack to read_file_system_list() above.
1540 ** It's not the most efficient approach, but consumes less memory. It
1541 ** also accommodates QNX's ability to mount filesystems on the fly.
1543 struct mount_entry
*entry
;
1544 struct fs_usage fs_use
;
1546 entry
= read_file_system_list ();
1549 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1551 myfs_stats
->type
= entry
->me_dev
;
1552 myfs_stats
->typename
= entry
->me_type
;
1553 myfs_stats
->mpoint
= entry
->me_mountdir
;
1554 myfs_stats
->mroot
= entry
->me_mntroot
;
1555 myfs_stats
->device
= entry
->me_devname
;
1557 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1558 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1559 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1560 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1563 #endif /* HAVE_INFOMOUNT_QNX */
1565 myfs_stats
->type
= 0;
1566 myfs_stats
->mpoint
= "unknown";
1567 myfs_stats
->device
= "unknown";
1568 myfs_stats
->avail
= 0;
1569 myfs_stats
->total
= 0;
1570 myfs_stats
->nfree
= 0;
1571 myfs_stats
->nodes
= 0;
1575 /* --------------------------------------------------------------------------------------------- */