2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * \brief Source: list of mounted filesystems
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
41 /* This header needs to be included before sys/mount.h on *BSD */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
46 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
47 #include <sys/statvfs.h>
49 /* Don't include backward-compatibility files unless they're needed.
50 Eventually we'd like to remove all this cruft. */
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
124 #ifdef MOUNTED_FREAD /* SVR2. */
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
134 #ifdef MOUNTED_LISTMNTENT
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
142 #ifdef MOUNTED_VMOUNT /* AIX. */
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
167 #define MNT_IGNORE(M) 0
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
204 #define ME_DUMMY_0(Fs_name, Fs_type) \
205 (strcmp (Fs_type, "autofs") == 0 \
206 || strcmp (Fs_type, "proc") == 0 \
207 || strcmp (Fs_type, "subfs") == 0 \
208 /* for NetBSD 3.0 */ \
209 || strcmp (Fs_type, "kernfs") == 0 \
211 || strcmp (Fs_type, "ignore") == 0)
213 /* Historically, we have marked as "dummy" any file system of type "none",
214 but now that programs like du need to know about bind-mounted directories,
215 we grant an exception to any with "bind" in its list of mount options.
216 I.e., those are *not* dummy entries. */
217 #ifdef MOUNTED_GETMNTENT1
218 #define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \
219 (ME_DUMMY_0 (Fs_name, Fs_type) \
220 || (strcmp (Fs_type, "none") == 0 \
221 && !hasmntopt (Fs_ent, "bind")))
223 #define ME_DUMMY(Fs_name, Fs_type) \
224 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
229 #define ME_REMOTE me_remote
230 /* All cygwin mount points include `:' or start with `//'; so it
231 requires a native Windows call to determine remote disks. */
233 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
235 if (fs_name
[0] && fs_name
[1] == ':')
238 sprintf (drive
, "%c:\\", fs_name
[0]);
239 switch (GetDriveType (drive
))
241 case DRIVE_REMOVABLE
:
252 /* A file system is `remote' if its Fs_name contains a `:'
253 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
254 #define ME_REMOTE(Fs_name, Fs_type) \
255 (strchr (Fs_name, ':') != NULL \
256 || ((Fs_name)[0] == '/' \
257 && (Fs_name)[1] == '/' \
258 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
261 /* Many space usage primitives use all 1 bits to denote a value that is
262 not applicable or unknown. Propagate this information by returning
263 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
264 is unsigned and narrower than uintmax_t. */
265 #define PROPAGATE_ALL_ONES(x) \
266 ((sizeof (x) < sizeof (uintmax_t) \
267 && (~ (x) == (sizeof (x) < sizeof (int) \
268 ? - (1 << (sizeof (x) * CHAR_BIT)) \
270 ? UINTMAX_MAX : (uintmax_t) (x))
272 /* Extract the top bit of X as an uintmax_t value. */
273 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
275 /* If a value is negative, many space usage primitives store it into an
276 integer variable by assignment, even if the variable's type is unsigned.
277 So, if a space usage variable X's top bit is set, convert X to the
278 uintmax_t value V such that (- (uintmax_t) V) is the negative of
279 the original value. If X's top bit is clear, just yield X.
280 Use PROPAGATE_TOP_BIT if the original value might be negative;
281 otherwise, use PROPAGATE_ALL_ONES. */
282 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
285 /* Return true if statvfs works. This is false for statvfs on systems
286 with GNU libc on Linux kernels before 2.6.36, which stats all
287 preceding entries in /proc/mounts; that makes df hang if even one
288 of the corresponding file systems is hard-mounted but not available. */
289 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
290 /* The FRSIZE fallback is not required in this case. */
291 #undef STAT_STATFS2_FRSIZE
298 #include <string.h> /* for strverscmp */
299 #include <sys/utsname.h>
300 #include <sys/statfs.h>
301 #define STAT_STATFS2_BSIZE 1
306 static int statvfs_works_cache
= -1;
309 if (statvfs_works_cache
< 0)
310 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= strverscmp (name
.release
, "2.6.36"));
311 return statvfs_works_cache
;
316 #ifdef STAT_READ_FILSYS /* SVR2 */
317 /* Set errno to zero upon EOF. */
318 #define ZERO_BYTE_TRANSFER_ERRNO 0
321 #define IS_EINTR(x) ((x) == EINTR)
323 #define IS_EINTR(x) 0
325 #endif /* STAT_READ_FILSYS */
327 /*** file scope type declarations ****************************************************************/
329 /* A mount table entry. */
332 char *me_devname
; /* Device node name, including "/dev/". */
333 char *me_mountdir
; /* Mount point directory name. */
334 char *me_type
; /* "nfs", "4.2", etc. */
335 dev_t me_dev
; /* Device number of me_mountdir. */
336 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
337 unsigned int me_remote
:1; /* Nonzero for remote fileystems. */
338 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
339 struct mount_entry
*me_next
;
344 uintmax_t fsu_blocksize
; /* Size of a block. */
345 uintmax_t fsu_blocks
; /* Total blocks. */
346 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
347 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
348 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
349 uintmax_t fsu_files
; /* Total file nodes. */
350 uintmax_t fsu_ffree
; /* Free file nodes. */
353 /*** file scope variables ************************************************************************/
355 #ifdef HAVE_INFOMOUNT_LIST
356 static struct mount_entry
*mc_mount_list
= NULL
;
357 #endif /* HAVE_INFOMOUNT_LIST */
359 /*** file scope functions ************************************************************************/
360 /* --------------------------------------------------------------------------------------------- */
362 #ifdef HAVE_INFOMOUNT_LIST
364 free_mount_entry (struct mount_entry
*me
)
368 g_free (me
->me_devname
);
369 g_free (me
->me_mountdir
);
370 if (me
->me_type_malloced
)
371 g_free (me
->me_type
);
375 /* --------------------------------------------------------------------------------------------- */
377 #ifdef MOUNTED_GETMNTINFO
379 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
381 fstype_to_string (short int t
)
473 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
475 /* --------------------------------------------------------------------------------------------- */
478 fsp_to_string (const struct statfs
*fsp
)
480 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
481 return (char *) (fsp
->f_fstypename
);
483 return fstype_to_string (fsp
->f_type
);
486 #endif /* MOUNTED_GETMNTINFO */
488 /* --------------------------------------------------------------------------------------------- */
490 #ifdef MOUNTED_VMOUNT /* AIX. */
492 fstype_to_string (int t
)
496 e
= getvfsbytype (t
);
497 if (!e
|| !e
->vfsent_name
)
500 return e
->vfsent_name
;
502 #endif /* MOUNTED_VMOUNT */
504 /* --------------------------------------------------------------------------------------------- */
506 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
508 /* Return the device number from MOUNT_OPTIONS, if possible.
509 Otherwise return (dev_t) -1. */
511 /* --------------------------------------------------------------------------------------------- */
514 dev_from_mount_options (char const *mount_options
)
516 /* GNU/Linux allows file system implementations to define their own
517 meaning for "dev=" mount options, so don't trust the meaning
520 static char const dev_pattern
[] = ",dev=";
521 char const *devopt
= strstr (mount_options
, dev_pattern
);
525 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
527 unsigned long int dev
;
529 dev
= strtoul (optval
, &optvalend
, 16);
530 if (optval
!= optvalend
531 && (*optvalend
== '\0' || *optvalend
== ',')
532 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
537 (void) mount_options
;
543 /* --------------------------------------------------------------------------------------------- */
545 #if defined _AIX && defined _I386
546 /* AIX PS/2 does not supply statfs. */
549 statfs (char *file
, struct statfs
*fsb
)
554 if (stat (file
, &stats
) != 0)
556 if (dustat (stats
.st_dev
, 0, &fsd
, sizeof (fsd
)))
559 fsb
->f_bsize
= fsd
.du_bsize
;
560 fsb
->f_blocks
= fsd
.du_fsize
- fsd
.du_isize
;
561 fsb
->f_bfree
= fsd
.du_tfree
;
562 fsb
->f_bavail
= fsd
.du_tfree
;
563 fsb
->f_files
= (fsd
.du_isize
- 2) * fsd
.du_inopb
;
564 fsb
->f_ffree
= fsd
.du_tinode
;
565 fsb
->f_fsid
.val
[0] = fsd
.du_site
;
566 fsb
->f_fsid
.val
[1] = fsd
.du_pckno
;
570 #endif /* _AIX && _I386 */
572 /* --------------------------------------------------------------------------------------------- */
574 /* Return a list of the currently mounted file systems, or NULL on error.
575 Add each entry to the tail of the list so that they stay in order.
576 If NEED_FS_TYPE is true, ensure that the file system type fields in
577 the returned list are valid. Otherwise, they might not be. */
579 static struct mount_entry
*
580 read_file_system_list (int need_fs_type
)
582 struct mount_entry
*mount_list
;
583 struct mount_entry
*me
;
584 struct mount_entry
**mtail
= &mount_list
;
586 #ifdef MOUNTED_LISTMNTENT
588 struct tabmntent
*mntlist
, *p
;
590 struct mount_entry
*me
;
592 /* the third and fourth arguments could be used to filter mounts,
593 but Crays doesn't seem to have any mounts that we want to
594 remove. Specifically, automount create normal NFS mounts.
597 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
599 for (p
= mntlist
; p
; p
= p
->next
)
602 me
= g_malloc (sizeof (*me
));
603 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
604 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
605 me
->me_type
= g_strdup (mnt
->mnt_type
);
606 me
->me_type_malloced
= 1;
607 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
608 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
611 mtail
= &me
->me_next
;
613 freemntlist (mntlist
);
617 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
620 const char *table
= MOUNTED
;
623 fp
= setmntent (table
, "r");
627 while ((mnt
= getmntent (fp
)))
629 me
= g_malloc (sizeof (*me
));
630 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
631 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
632 me
->me_type
= g_strdup (mnt
->mnt_type
);
633 me
->me_type_malloced
= 1;
634 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, mnt
);
635 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
636 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
638 /* Add to the linked list. */
640 mtail
= &me
->me_next
;
643 if (endmntent (fp
) == 0)
646 #endif /* MOUNTED_GETMNTENT1. */
648 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
653 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
656 for (; entries
-- > 0; fsp
++)
658 char *fs_type
= fsp_to_string (fsp
);
660 me
= g_malloc (sizeof (*me
));
661 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
662 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
663 me
->me_type
= fs_type
;
664 me
->me_type_malloced
= 0;
665 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
666 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
667 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
669 /* Add to the linked list. */
671 mtail
= &me
->me_next
;
674 #endif /* MOUNTED_GETMNTINFO */
676 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
681 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
684 for (; entries
-- > 0; fsp
++)
686 me
= g_malloc (sizeof (*me
));
687 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
688 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
689 me
->me_type
= g_strdup (fsp
->f_fstypename
);
690 me
->me_type_malloced
= 1;
691 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
692 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
693 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
695 /* Add to the linked list. */
697 mtail
= &me
->me_next
;
700 #endif /* MOUNTED_GETMNTINFO2 */
702 #ifdef MOUNTED_GETMNT /* Ultrix. */
708 while (errno
= 0, 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) 0)))
710 me
= g_malloc (sizeof (*me
));
711 me
->me_devname
= g_strdup (fsd
.fd_req
.devname
);
712 me
->me_mountdir
= g_strdup (fsd
.fd_req
.path
);
713 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
714 me
->me_type_malloced
= 0;
715 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
716 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
717 me
->me_dev
= fsd
.fd_req
.dev
;
719 /* Add to the linked list. */
721 mtail
= &me
->me_next
;
726 #endif /* MOUNTED_GETMNT. */
728 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
730 /* The next_dev() and fs_stat_dev() system calls give the list of
731 all file systems, including the information returned by statvfs()
732 (fs type, total blocks, free blocks etc.), but without the mount
733 point. But on BeOS all file systems except / are mounted in the
734 rootfs, directly under /.
735 The directory name of the mount point is often, but not always,
736 identical to the volume name of the device.
737 We therefore get the list of subdirectories of /, and the list
738 of all file systems, and match the two lists. */
746 struct rootdir_entry
*next
;
748 struct rootdir_entry
*rootdir_list
;
749 struct rootdir_entry
**rootdir_tail
;
754 /* All volumes are mounted in the rootfs, directly under /. */
756 rootdir_tail
= &rootdir_list
;
757 dirp
= opendir ("/");
762 while ((d
= readdir (dirp
)) != NULL
)
767 if (strcmp (d
->d_name
, "..") == 0)
770 if (strcmp (d
->d_name
, ".") == 0)
771 name
= g_strdup ("/");
773 name
= g_strconcat ("/", d
->d_name
, (char *) NULL
);
775 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
777 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
779 re
->dev
= statbuf
.st_dev
;
780 re
->ino
= statbuf
.st_ino
;
782 /* Add to the linked list. */
784 rootdir_tail
= &re
->next
;
791 *rootdir_tail
= NULL
;
793 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
794 if (fs_stat_dev (dev
, &fi
) >= 0)
796 /* Note: fi.dev == dev. */
797 struct rootdir_entry
*re
;
799 for (re
= rootdir_list
; re
; re
= re
->next
)
800 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
803 me
= g_malloc (sizeof (*me
));
804 me
->me_devname
= g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
805 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
806 me
->me_type
= g_strdup (fi
.fsh_name
);
807 me
->me_type_malloced
= 1;
810 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
812 /* Add to the linked list. */
814 mtail
= &me
->me_next
;
818 while (rootdir_list
!= NULL
)
820 struct rootdir_entry
*re
= rootdir_list
;
821 rootdir_list
= re
->next
;
826 #endif /* MOUNTED_FS_STAT_DEV */
828 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
832 struct statfs
*stats
;
834 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
837 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
839 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
843 bufsize
= (1 + numsys
) * sizeof (*stats
);
844 stats
= g_malloc (bufsize
);
845 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
853 for (counter
= 0; counter
< numsys
; counter
++)
855 me
= g_malloc (sizeof (*me
));
856 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
857 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
858 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
859 me
->me_type_malloced
= 1;
860 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
861 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
862 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
864 /* Add to the linked list. */
866 mtail
= &me
->me_next
;
871 #endif /* MOUNTED_GETFSSTAT */
873 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
876 char *table
= "/etc/mnttab";
879 fp
= fopen (table
, "r");
883 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
885 me
= g_malloc (sizeof (*me
));
886 #ifdef GETFSTYP /* SVR3. */
887 me
->me_devname
= g_strdup (mnt
.mt_dev
);
889 me
->me_devname
= g_strconcat ("/dev/", mnt
.mt_dev
, (char *) NULL
);
891 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
892 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
894 me
->me_type_malloced
= 0;
895 #ifdef GETFSTYP /* SVR3. */
899 char typebuf
[FSTYPSZ
];
901 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
902 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
904 me
->me_type
= g_strdup (typebuf
);
905 me
->me_type_malloced
= 1;
909 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
910 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
912 /* Add to the linked list. */
914 mtail
= &me
->me_next
;
919 /* The last fread() call must have failed. */
920 int saved_errno
= errno
;
926 if (fclose (fp
) == EOF
)
929 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
931 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
933 struct mntent
**mnttbl
= getmnttbl (), **ent
;
934 for (ent
= mnttbl
; *ent
; ent
++)
936 me
= g_malloc (sizeof (*me
));
937 me
->me_devname
= g_strdup ((*ent
)->mt_resource
);
938 me
->me_mountdir
= g_strdup ((*ent
)->mt_directory
);
939 me
->me_type
= g_strdup ((*ent
)->mt_fstype
);
940 me
->me_type_malloced
= 1;
941 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
942 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
943 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
945 /* Add to the linked list. */
947 mtail
= &me
->me_next
;
953 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
956 char *table
= MNTTAB
;
961 #if defined F_RDLCK && defined F_SETLKW
962 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
963 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
964 for this file name, we should use their macro name instead.
965 (Why not just lock MNTTAB directly? We don't know.) */
967 #define MNTTAB_LOCK "/etc/.mnttab.lock"
969 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
973 flock
.l_type
= F_RDLCK
;
974 flock
.l_whence
= SEEK_SET
;
977 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
980 int saved_errno
= errno
;
986 else if (errno
!= ENOENT
)
991 fp
= fopen (table
, "r");
996 while ((ret
= getmntent (fp
, &mnt
)) == 0)
998 me
= g_malloc (sizeof (*me
));
999 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1000 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1001 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1002 me
->me_type_malloced
= 1;
1003 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1004 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1005 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1007 /* Add to the linked list. */
1009 mtail
= &me
->me_next
;
1012 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1015 if (0 <= lockfd
&& close (lockfd
) != 0)
1021 goto free_then_fail
;
1024 #endif /* MOUNTED_GETMNTENT2. */
1026 #ifdef MOUNTED_VMOUNT /* AIX. */
1029 char *entries
, *thisent
;
1034 /* Ask how many bytes to allocate for the mounted file system info. */
1035 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), (struct vmount
*) &bufsize
) != 0)
1037 entries
= g_malloc (bufsize
);
1039 /* Get the list of mounted file systems. */
1040 n_entries
= mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
1043 int saved_errno
= errno
;
1045 errno
= saved_errno
;
1049 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1051 char *options
, *ignore
;
1053 vmp
= (struct vmount
*) thisent
;
1054 me
= g_malloc (sizeof (*me
));
1055 if (vmp
->vmt_flags
& MNT_REMOTE
)
1060 /* Prepend the remote dirname. */
1061 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1062 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1063 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1068 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1070 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1071 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1072 me
->me_type_malloced
= 1;
1073 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1074 ignore
= strstr (options
, "ignore");
1075 me
->me_dummy
= (ignore
1076 && (ignore
== options
|| ignore
[-1] == ',')
1077 && (ignore
[sizeof ("ignore") - 1] == ','
1078 || ignore
[sizeof ("ignore") - 1] == '\0'));
1079 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1081 /* Add to the linked list. */
1083 mtail
= &me
->me_next
;
1087 #endif /* MOUNTED_VMOUNT. */
1090 #ifdef MOUNTED_INTERIX_STATVFS
1092 DIR *dirp
= opendir ("/dev/fs");
1093 char node
[9 + NAME_MAX
];
1096 goto free_then_fail
;
1101 struct dirent entry
;
1102 struct dirent
*result
;
1104 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1107 strcpy (node
, "/dev/fs/");
1108 strcat (node
, entry
.d_name
);
1110 if (statvfs (node
, &dev
) == 0)
1112 me
= g_malloc (sizeof *me
);
1113 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1114 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1115 me
->me_type
= g_strdup (dev
.f_fstypename
);
1116 me
->me_type_malloced
= 1;
1117 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1118 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1119 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1121 /* Add to the linked list. */
1123 mtail
= &me
->me_next
;
1127 #endif /* MOUNTED_INTERIX_STATVFS */
1129 (void) need_fs_type
; /* avoid argument-unused warning */
1136 int saved_errno
= errno
;
1141 me
= mount_list
->me_next
;
1142 g_free (mount_list
->me_devname
);
1143 g_free (mount_list
->me_mountdir
);
1144 if (mount_list
->me_type_malloced
)
1145 g_free (mount_list
->me_type
);
1146 g_free (mount_list
);
1150 errno
= saved_errno
;
1155 #endif /* HAVE_INFOMOUNT_LIST */
1157 /* --------------------------------------------------------------------------------------------- */
1159 #ifdef HAVE_INFOMOUNT_QNX
1161 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1162 ** this via the following code.
1163 ** Note that, as this is based on CWD, it only fills one mount_entry
1164 ** structure. See my_statfs() in utilunix.c for the "other side" of
1168 static struct mount_entry
*
1169 read_file_system_list (int need_fs_type
, int all_fs
)
1171 struct _disk_entry de
;
1174 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1176 static struct mount_entry
*me
= NULL
;
1180 g_free (me
->me_devname
);
1181 g_free (me
->me_mountdir
);
1182 g_free (me
->me_type
);
1185 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1187 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1190 fd
= open (dir
, O_RDONLY
);
1194 i
= disk_get_entry (fd
, &de
);
1201 switch (de
.disk_type
)
1228 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1231 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1234 me
->me_devname
= g_strdup (dev
);
1235 me
->me_mountdir
= g_strdup (dir
);
1236 me
->me_type
= g_strdup (tp
);
1237 me
->me_dev
= de
.disk_type
;
1241 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1242 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1243 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1244 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1249 #endif /* HAVE_INFOMOUNT_QNX */
1251 /* --------------------------------------------------------------------------------------------- */
1253 #ifdef STAT_READ_FILSYS /* SVR2 */
1255 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1256 interrupted. Return the actual number of bytes read(written), zero for EOF,
1257 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1259 safe_read (int fd
, void *buf
, size_t count
)
1261 /* Work around a bug in Tru64 5.1. Attempting to read more than
1262 INT_MAX bytes fails with errno == EINVAL. See
1263 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1264 When decreasing COUNT, keep it block-aligned. */
1266 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1271 ssize_t result
= read (fd
, buf
, count
);
1275 else if (IS_EINTR (errno
))
1277 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1278 count
= BUGGY_READ_MAXIMUM
;
1284 /* --------------------------------------------------------------------------------------------- */
1286 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1287 interrupted or if a partial write(read) occurs. Return the number
1288 of bytes transferred.
1289 When writing, set errno if fewer than COUNT bytes are written.
1290 When reading, if fewer than COUNT bytes are read, you must examine
1291 errno to distinguish failure from EOF (errno == 0). */
1294 full_read (int fd
, void *buf
, size_t count
)
1297 char *ptr
= (char *) buf
;
1301 size_t n_rw
= safe_read (fd
, ptr
, count
);
1302 if (n_rw
== (size_t) (-1))
1306 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1317 #endif /* STAT_READ_FILSYS */
1319 /* --------------------------------------------------------------------------------------------- */
1321 #ifdef HAVE_INFOMOUNT
1322 /* Fill in the fields of FSP with information about space usage for
1323 the file system on which FILE resides.
1324 DISK is the device on which FILE is mounted, for space-getting
1325 methods that need to know it.
1326 Return 0 if successful, -1 if not. When returning -1, ensure that
1327 ERRNO is either a system error value, or zero if DISK is NULL
1328 on a system that requires a non-NULL value. */
1330 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1332 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1334 if (statvfs_works ())
1336 struct statvfs vfsd
;
1338 if (statvfs (file
, &vfsd
) < 0)
1341 /* f_frsize isn't guaranteed to be supported. */
1342 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1343 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1344 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1346 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1347 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1348 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1349 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1350 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1351 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1357 #if defined STAT_STATVFS64 /* AIX */
1359 struct statvfs64 fsd
;
1361 if (statvfs64 (file
, &fsd
) < 0)
1364 /* f_frsize isn't guaranteed to be supported. */
1366 fsp
->fsu_blocksize
= fsd
.f_frsize
1367 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1368 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1371 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1375 if (statfs (file
, &fsd
) != 1)
1378 fsp
->fsu_blocksize
= 1024;
1379 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1380 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1381 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1382 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1383 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1384 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1386 #elif defined STAT_READ_FILSYS /* SVR2 */
1388 #define SUPERBOFF (SUPERB * 512)
1400 fd
= open (disk
, O_RDONLY
);
1403 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1404 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1411 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1412 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1413 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1414 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1415 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1416 fsp
->fsu_files
= (fsd
.s_isize
== -1
1417 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1418 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1420 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1424 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1427 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1429 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1433 if (statfs (file
, &fsd
) < 0)
1436 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1438 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1439 Mac OS X < 10.4, FreeBSD < 5.0, \
1440 NetBSD < 3.0, OpenBSD < 4.4 */
1444 if (statfs (file
, &fsd
) < 0)
1447 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1449 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1451 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1452 struct statfs are truncated to 2GB. These conditions detect that
1453 truncation, presumably without botching the 4.1.1 case, in which
1454 the values are not truncated. The correct counts are stored in
1455 undocumented spare fields. */
1456 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1458 fsd
.f_blocks
= fsd
.f_spare
[0];
1459 fsd
.f_bfree
= fsd
.f_spare
[1];
1460 fsd
.f_bavail
= fsd
.f_spare
[2];
1462 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1464 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1468 if (statfs (file
, &fsd
) < 0)
1471 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1473 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1476 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1477 #define f_bavail f_bfree
1482 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1485 /* Empirically, the block counts on most SVR3 and SVR3-derived
1486 systems seem to always be in terms of 512-byte blocks,
1487 no matter what value f_bsize has. */
1488 #if defined _AIX || defined _CRAY
1489 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1491 fsp
->fsu_blocksize
= 512;
1496 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1497 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1498 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1500 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1501 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1502 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1503 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1504 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1505 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1510 (void) disk
; /* avoid argument-unused warning */
1514 #endif /* HAVE_INFOMOUNT */
1516 /* --------------------------------------------------------------------------------------------- */
1517 /*** public functions ****************************************************************************/
1518 /* --------------------------------------------------------------------------------------------- */
1521 free_my_statfs (void)
1523 #ifdef HAVE_INFOMOUNT_LIST
1524 while (mc_mount_list
!= NULL
)
1526 struct mount_entry
*next
;
1528 next
= mc_mount_list
->me_next
;
1529 free_mount_entry (mc_mount_list
);
1530 mc_mount_list
= next
;
1533 mc_mount_list
= NULL
;
1534 #endif /* HAVE_INFOMOUNT_LIST */
1537 /* --------------------------------------------------------------------------------------------- */
1540 init_my_statfs (void)
1542 #ifdef HAVE_INFOMOUNT_LIST
1544 mc_mount_list
= read_file_system_list (1);
1545 #endif /* HAVE_INFOMOUNT_LIST */
1548 /* --------------------------------------------------------------------------------------------- */
1551 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1553 #ifdef HAVE_INFOMOUNT_LIST
1555 struct mount_entry
*entry
= NULL
;
1556 struct mount_entry
*temp
= mc_mount_list
;
1557 struct fs_usage fs_use
;
1561 i
= strlen (temp
->me_mountdir
);
1562 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1563 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == '\0'))
1568 temp
= temp
->me_next
;
1573 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1574 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1576 myfs_stats
->type
= entry
->me_dev
;
1577 myfs_stats
->typename
= entry
->me_type
;
1578 myfs_stats
->mpoint
= entry
->me_mountdir
;
1579 myfs_stats
->device
= entry
->me_devname
;
1581 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1582 fs_use
.fsu_blocksize
) >> 10;
1583 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1584 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1585 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1588 #endif /* HAVE_INFOMOUNT_LIST */
1590 #ifdef HAVE_INFOMOUNT_QNX
1592 ** This is the "other side" of the hack to read_file_system_list() in
1594 ** It's not the most efficient approach, but consumes less memory. It
1595 ** also accomodates QNX's ability to mount filesystems on the fly.
1597 struct mount_entry
*entry
;
1598 struct fs_usage fs_use
;
1600 entry
= read_file_system_list (0, 0);
1603 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1605 myfs_stats
->type
= entry
->me_dev
;
1606 myfs_stats
->typename
= entry
->me_type
;
1607 myfs_stats
->mpoint
= entry
->me_mountdir
;
1608 myfs_stats
->device
= entry
->me_devname
;
1610 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1611 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1612 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1613 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1616 #endif /* HAVE_INFOMOUNT_QNX */
1618 myfs_stats
->type
= 0;
1619 myfs_stats
->mpoint
= "unknown";
1620 myfs_stats
->device
= "unknown";
1621 myfs_stats
->avail
= 0;
1622 myfs_stats
->total
= 0;
1623 myfs_stats
->nfree
= 0;
1624 myfs_stats
->nodes
= 0;
1628 /* --------------------------------------------------------------------------------------------- */