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 Linux 2.6/3.x */ \
209 || strcmp (Fs_type, "debugfs") == 0 \
210 || strcmp (Fs_type, "devpts") == 0 \
211 || strcmp (Fs_type, "devtmpfs") == 0 \
212 || strcmp (Fs_type, "fusectl") == 0 \
213 || strcmp (Fs_type, "mqueue") == 0 \
214 || strcmp (Fs_type, "rpc_pipefs") == 0 \
215 || strcmp (Fs_type, "sysfs") == 0 \
216 /* FreeBSD, Linux 2.4 */ \
217 || strcmp (Fs_type, "devfs") == 0 \
218 /* for NetBSD 3.0 */ \
219 || strcmp (Fs_type, "kernfs") == 0 \
221 || strcmp (Fs_type, "ignore") == 0)
223 /* Historically, we have marked as "dummy" any file system of type "none",
224 but now that programs like du need to know about bind-mounted directories,
225 we grant an exception to any with "bind" in its list of mount options.
226 I.e., those are *not* dummy entries. */
227 #ifdef MOUNTED_GETMNTENT1
228 #define ME_DUMMY(Fs_name, Fs_type, Fs_ent) \
229 (ME_DUMMY_0 (Fs_name, Fs_type) \
230 || (strcmp (Fs_type, "none") == 0 \
231 && !hasmntopt (Fs_ent, "bind")))
233 #define ME_DUMMY(Fs_name, Fs_type) \
234 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
239 #define ME_REMOTE me_remote
240 /* All cygwin mount points include `:' or start with `//'; so it
241 requires a native Windows call to determine remote disks. */
243 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
245 if (fs_name
[0] && fs_name
[1] == ':')
248 sprintf (drive
, "%c:\\", fs_name
[0]);
249 switch (GetDriveType (drive
))
251 case DRIVE_REMOVABLE
:
262 /* A file system is `remote' if its Fs_name contains a `:'
263 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
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 || strcmp (Fs_type, "cifs") == 0)))
271 /* Many space usage primitives use all 1 bits to denote a value that is
272 not applicable or unknown. Propagate this information by returning
273 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
274 is unsigned and narrower than uintmax_t. */
275 #define PROPAGATE_ALL_ONES(x) \
276 ((sizeof (x) < sizeof (uintmax_t) \
277 && (~ (x) == (sizeof (x) < sizeof (int) \
278 ? - (1 << (sizeof (x) * CHAR_BIT)) \
280 ? UINTMAX_MAX : (uintmax_t) (x))
282 /* Extract the top bit of X as an uintmax_t value. */
283 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
285 /* If a value is negative, many space usage primitives store it into an
286 integer variable by assignment, even if the variable's type is unsigned.
287 So, if a space usage variable X's top bit is set, convert X to the
288 uintmax_t value V such that (- (uintmax_t) V) is the negative of
289 the original value. If X's top bit is clear, just yield X.
290 Use PROPAGATE_TOP_BIT if the original value might be negative;
291 otherwise, use PROPAGATE_ALL_ONES. */
292 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
295 /* Return true if statvfs works. This is false for statvfs on systems
296 with GNU libc on Linux kernels before 2.6.36, which stats all
297 preceding entries in /proc/mounts; that makes df hang if even one
298 of the corresponding file systems is hard-mounted but not available. */
299 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
300 /* The FRSIZE fallback is not required in this case. */
301 #undef STAT_STATFS2_FRSIZE
308 #include <string.h> /* for strverscmp */
309 #include <sys/utsname.h>
310 #include <sys/statfs.h>
311 #define STAT_STATFS2_BSIZE 1
316 static int statvfs_works_cache
= -1;
319 if (statvfs_works_cache
< 0)
320 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= strverscmp (name
.release
, "2.6.36"));
321 return statvfs_works_cache
;
326 #ifdef STAT_READ_FILSYS /* SVR2 */
327 /* Set errno to zero upon EOF. */
328 #define ZERO_BYTE_TRANSFER_ERRNO 0
331 #define IS_EINTR(x) ((x) == EINTR)
333 #define IS_EINTR(x) 0
335 #endif /* STAT_READ_FILSYS */
337 /*** file scope type declarations ****************************************************************/
339 /* A mount table entry. */
342 char *me_devname
; /* Device node name, including "/dev/". */
343 char *me_mountdir
; /* Mount point directory name. */
344 char *me_type
; /* "nfs", "4.2", etc. */
345 dev_t me_dev
; /* Device number of me_mountdir. */
346 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
347 unsigned int me_remote
:1; /* Nonzero for remote fileystems. */
348 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
349 struct mount_entry
*me_next
;
354 uintmax_t fsu_blocksize
; /* Size of a block. */
355 uintmax_t fsu_blocks
; /* Total blocks. */
356 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
357 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
358 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
359 uintmax_t fsu_files
; /* Total file nodes. */
360 uintmax_t fsu_ffree
; /* Free file nodes. */
363 /*** file scope variables ************************************************************************/
365 #ifdef HAVE_INFOMOUNT_LIST
366 static struct mount_entry
*mc_mount_list
= NULL
;
367 #endif /* HAVE_INFOMOUNT_LIST */
369 /*** file scope functions ************************************************************************/
370 /* --------------------------------------------------------------------------------------------- */
372 #ifdef HAVE_INFOMOUNT_LIST
374 free_mount_entry (struct mount_entry
*me
)
378 g_free (me
->me_devname
);
379 g_free (me
->me_mountdir
);
380 if (me
->me_type_malloced
)
381 g_free (me
->me_type
);
385 /* --------------------------------------------------------------------------------------------- */
387 #ifdef MOUNTED_GETMNTINFO
389 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
391 fstype_to_string (short int t
)
483 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
485 /* --------------------------------------------------------------------------------------------- */
488 fsp_to_string (const struct statfs
*fsp
)
490 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
491 return (char *) (fsp
->f_fstypename
);
493 return fstype_to_string (fsp
->f_type
);
496 #endif /* MOUNTED_GETMNTINFO */
498 /* --------------------------------------------------------------------------------------------- */
500 #ifdef MOUNTED_VMOUNT /* AIX. */
502 fstype_to_string (int t
)
506 e
= getvfsbytype (t
);
507 if (!e
|| !e
->vfsent_name
)
510 return e
->vfsent_name
;
512 #endif /* MOUNTED_VMOUNT */
514 /* --------------------------------------------------------------------------------------------- */
516 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
518 /* Return the device number from MOUNT_OPTIONS, if possible.
519 Otherwise return (dev_t) -1. */
521 /* --------------------------------------------------------------------------------------------- */
524 dev_from_mount_options (char const *mount_options
)
526 /* GNU/Linux allows file system implementations to define their own
527 meaning for "dev=" mount options, so don't trust the meaning
530 static char const dev_pattern
[] = ",dev=";
531 char const *devopt
= strstr (mount_options
, dev_pattern
);
535 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
537 unsigned long int dev
;
539 dev
= strtoul (optval
, &optvalend
, 16);
540 if (optval
!= optvalend
541 && (*optvalend
== '\0' || *optvalend
== ',')
542 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
547 (void) mount_options
;
553 /* --------------------------------------------------------------------------------------------- */
555 #if defined _AIX && defined _I386
556 /* AIX PS/2 does not supply statfs. */
559 statfs (char *file
, struct statfs
*fsb
)
564 if (stat (file
, &stats
) != 0)
566 if (dustat (stats
.st_dev
, 0, &fsd
, sizeof (fsd
)))
569 fsb
->f_bsize
= fsd
.du_bsize
;
570 fsb
->f_blocks
= fsd
.du_fsize
- fsd
.du_isize
;
571 fsb
->f_bfree
= fsd
.du_tfree
;
572 fsb
->f_bavail
= fsd
.du_tfree
;
573 fsb
->f_files
= (fsd
.du_isize
- 2) * fsd
.du_inopb
;
574 fsb
->f_ffree
= fsd
.du_tinode
;
575 fsb
->f_fsid
.val
[0] = fsd
.du_site
;
576 fsb
->f_fsid
.val
[1] = fsd
.du_pckno
;
580 #endif /* _AIX && _I386 */
582 /* --------------------------------------------------------------------------------------------- */
584 /* Return a list of the currently mounted file systems, or NULL on error.
585 Add each entry to the tail of the list so that they stay in order.
586 If NEED_FS_TYPE is true, ensure that the file system type fields in
587 the returned list are valid. Otherwise, they might not be. */
589 static struct mount_entry
*
590 read_file_system_list (int need_fs_type
)
592 struct mount_entry
*mount_list
;
593 struct mount_entry
*me
;
594 struct mount_entry
**mtail
= &mount_list
;
596 #ifdef MOUNTED_LISTMNTENT
598 struct tabmntent
*mntlist
, *p
;
600 struct mount_entry
*me
;
602 /* the third and fourth arguments could be used to filter mounts,
603 but Crays doesn't seem to have any mounts that we want to
604 remove. Specifically, automount create normal NFS mounts.
607 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
609 for (p
= mntlist
; p
; p
= p
->next
)
612 me
= g_malloc (sizeof (*me
));
613 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
614 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
615 me
->me_type
= g_strdup (mnt
->mnt_type
);
616 me
->me_type_malloced
= 1;
617 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
618 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
621 mtail
= &me
->me_next
;
623 freemntlist (mntlist
);
627 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
630 const char *table
= MOUNTED
;
633 fp
= setmntent (table
, "r");
637 while ((mnt
= getmntent (fp
)))
639 me
= g_malloc (sizeof (*me
));
640 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
641 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
642 me
->me_type
= g_strdup (mnt
->mnt_type
);
643 me
->me_type_malloced
= 1;
644 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, mnt
);
645 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
646 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
648 /* Add to the linked list. */
650 mtail
= &me
->me_next
;
653 if (endmntent (fp
) == 0)
656 #endif /* MOUNTED_GETMNTENT1. */
658 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
663 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
666 for (; entries
-- > 0; fsp
++)
668 char *fs_type
= fsp_to_string (fsp
);
670 me
= g_malloc (sizeof (*me
));
671 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
672 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
673 me
->me_type
= fs_type
;
674 me
->me_type_malloced
= 0;
675 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
676 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
677 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
679 /* Add to the linked list. */
681 mtail
= &me
->me_next
;
684 #endif /* MOUNTED_GETMNTINFO */
686 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
691 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
694 for (; entries
-- > 0; fsp
++)
696 me
= g_malloc (sizeof (*me
));
697 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
698 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
699 me
->me_type
= g_strdup (fsp
->f_fstypename
);
700 me
->me_type_malloced
= 1;
701 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
702 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
703 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
705 /* Add to the linked list. */
707 mtail
= &me
->me_next
;
710 #endif /* MOUNTED_GETMNTINFO2 */
712 #ifdef MOUNTED_GETMNT /* Ultrix. */
718 while (errno
= 0, 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) 0)))
720 me
= g_malloc (sizeof (*me
));
721 me
->me_devname
= g_strdup (fsd
.fd_req
.devname
);
722 me
->me_mountdir
= g_strdup (fsd
.fd_req
.path
);
723 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
724 me
->me_type_malloced
= 0;
725 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
726 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
727 me
->me_dev
= fsd
.fd_req
.dev
;
729 /* Add to the linked list. */
731 mtail
= &me
->me_next
;
736 #endif /* MOUNTED_GETMNT. */
738 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
740 /* The next_dev() and fs_stat_dev() system calls give the list of
741 all file systems, including the information returned by statvfs()
742 (fs type, total blocks, free blocks etc.), but without the mount
743 point. But on BeOS all file systems except / are mounted in the
744 rootfs, directly under /.
745 The directory name of the mount point is often, but not always,
746 identical to the volume name of the device.
747 We therefore get the list of subdirectories of /, and the list
748 of all file systems, and match the two lists. */
756 struct rootdir_entry
*next
;
758 struct rootdir_entry
*rootdir_list
;
759 struct rootdir_entry
**rootdir_tail
;
764 /* All volumes are mounted in the rootfs, directly under /. */
766 rootdir_tail
= &rootdir_list
;
767 dirp
= opendir ("/");
772 while ((d
= readdir (dirp
)) != NULL
)
777 if (strcmp (d
->d_name
, "..") == 0)
780 if (strcmp (d
->d_name
, ".") == 0)
781 name
= g_strdup ("/");
783 name
= g_strconcat ("/", d
->d_name
, (char *) NULL
);
785 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
787 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
789 re
->dev
= statbuf
.st_dev
;
790 re
->ino
= statbuf
.st_ino
;
792 /* Add to the linked list. */
794 rootdir_tail
= &re
->next
;
801 *rootdir_tail
= NULL
;
803 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
804 if (fs_stat_dev (dev
, &fi
) >= 0)
806 /* Note: fi.dev == dev. */
807 struct rootdir_entry
*re
;
809 for (re
= rootdir_list
; re
; re
= re
->next
)
810 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
813 me
= g_malloc (sizeof (*me
));
815 g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
816 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
817 me
->me_type
= g_strdup (fi
.fsh_name
);
818 me
->me_type_malloced
= 1;
821 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
823 /* Add to the linked list. */
825 mtail
= &me
->me_next
;
829 while (rootdir_list
!= NULL
)
831 struct rootdir_entry
*re
= rootdir_list
;
832 rootdir_list
= re
->next
;
837 #endif /* MOUNTED_FS_STAT_DEV */
839 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
843 struct statfs
*stats
;
845 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
848 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
850 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
854 bufsize
= (1 + numsys
) * sizeof (*stats
);
855 stats
= g_malloc (bufsize
);
856 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
864 for (counter
= 0; counter
< numsys
; counter
++)
866 me
= g_malloc (sizeof (*me
));
867 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
868 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
869 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
870 me
->me_type_malloced
= 1;
871 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
872 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
873 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
875 /* Add to the linked list. */
877 mtail
= &me
->me_next
;
882 #endif /* MOUNTED_GETFSSTAT */
884 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
887 char *table
= "/etc/mnttab";
890 fp
= fopen (table
, "r");
894 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
896 me
= g_malloc (sizeof (*me
));
897 #ifdef GETFSTYP /* SVR3. */
898 me
->me_devname
= g_strdup (mnt
.mt_dev
);
900 me
->me_devname
= g_strconcat ("/dev/", mnt
.mt_dev
, (char *) NULL
);
902 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
903 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
905 me
->me_type_malloced
= 0;
906 #ifdef GETFSTYP /* SVR3. */
910 char typebuf
[FSTYPSZ
];
912 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
913 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
915 me
->me_type
= g_strdup (typebuf
);
916 me
->me_type_malloced
= 1;
920 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
921 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
923 /* Add to the linked list. */
925 mtail
= &me
->me_next
;
930 /* The last fread() call must have failed. */
931 int saved_errno
= errno
;
937 if (fclose (fp
) == EOF
)
940 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
942 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
944 struct mntent
**mnttbl
= getmnttbl (), **ent
;
945 for (ent
= mnttbl
; *ent
; ent
++)
947 me
= g_malloc (sizeof (*me
));
948 me
->me_devname
= g_strdup ((*ent
)->mt_resource
);
949 me
->me_mountdir
= g_strdup ((*ent
)->mt_directory
);
950 me
->me_type
= g_strdup ((*ent
)->mt_fstype
);
951 me
->me_type_malloced
= 1;
952 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
953 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
954 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
956 /* Add to the linked list. */
958 mtail
= &me
->me_next
;
964 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
967 char *table
= MNTTAB
;
972 #if defined F_RDLCK && defined F_SETLKW
973 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
974 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
975 for this file name, we should use their macro name instead.
976 (Why not just lock MNTTAB directly? We don't know.) */
978 #define MNTTAB_LOCK "/etc/.mnttab.lock"
980 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
984 flock
.l_type
= F_RDLCK
;
985 flock
.l_whence
= SEEK_SET
;
988 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
991 int saved_errno
= errno
;
997 else if (errno
!= ENOENT
)
1002 fp
= fopen (table
, "r");
1007 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1009 me
= g_malloc (sizeof (*me
));
1010 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1011 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1012 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1013 me
->me_type_malloced
= 1;
1014 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1015 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1016 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1018 /* Add to the linked list. */
1020 mtail
= &me
->me_next
;
1023 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1026 if (0 <= lockfd
&& close (lockfd
) != 0)
1032 goto free_then_fail
;
1035 #endif /* MOUNTED_GETMNTENT2. */
1037 #ifdef MOUNTED_VMOUNT /* AIX. */
1040 char *entries
, *thisent
;
1045 /* Ask how many bytes to allocate for the mounted file system info. */
1046 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), (struct vmount
*) &bufsize
) != 0)
1048 entries
= g_malloc (bufsize
);
1050 /* Get the list of mounted file systems. */
1051 n_entries
= mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
1054 int saved_errno
= errno
;
1056 errno
= saved_errno
;
1060 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1062 char *options
, *ignore
;
1064 vmp
= (struct vmount
*) thisent
;
1065 me
= g_malloc (sizeof (*me
));
1066 if (vmp
->vmt_flags
& MNT_REMOTE
)
1071 /* Prepend the remote dirname. */
1072 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1073 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1074 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1079 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1081 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1082 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1083 me
->me_type_malloced
= 1;
1084 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1085 ignore
= strstr (options
, "ignore");
1086 me
->me_dummy
= (ignore
1087 && (ignore
== options
|| ignore
[-1] == ',')
1088 && (ignore
[sizeof ("ignore") - 1] == ','
1089 || ignore
[sizeof ("ignore") - 1] == '\0'));
1090 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1092 /* Add to the linked list. */
1094 mtail
= &me
->me_next
;
1098 #endif /* MOUNTED_VMOUNT. */
1101 #ifdef MOUNTED_INTERIX_STATVFS
1103 DIR *dirp
= opendir ("/dev/fs");
1104 char node
[9 + NAME_MAX
];
1107 goto free_then_fail
;
1112 struct dirent entry
;
1113 struct dirent
*result
;
1115 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1118 strcpy (node
, "/dev/fs/");
1119 strcat (node
, entry
.d_name
);
1121 if (statvfs (node
, &dev
) == 0)
1123 me
= g_malloc (sizeof *me
);
1124 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1125 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1126 me
->me_type
= g_strdup (dev
.f_fstypename
);
1127 me
->me_type_malloced
= 1;
1128 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1129 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1130 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1132 /* Add to the linked list. */
1134 mtail
= &me
->me_next
;
1138 #endif /* MOUNTED_INTERIX_STATVFS */
1140 (void) need_fs_type
; /* avoid argument-unused warning */
1147 int saved_errno
= errno
;
1152 me
= mount_list
->me_next
;
1153 g_free (mount_list
->me_devname
);
1154 g_free (mount_list
->me_mountdir
);
1155 if (mount_list
->me_type_malloced
)
1156 g_free (mount_list
->me_type
);
1157 g_free (mount_list
);
1161 errno
= saved_errno
;
1166 #endif /* HAVE_INFOMOUNT_LIST */
1168 /* --------------------------------------------------------------------------------------------- */
1170 #ifdef HAVE_INFOMOUNT_QNX
1172 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1173 ** this via the following code.
1174 ** Note that, as this is based on CWD, it only fills one mount_entry
1175 ** structure. See my_statfs() in utilunix.c for the "other side" of
1179 static struct mount_entry
*
1180 read_file_system_list (int need_fs_type
, int all_fs
)
1182 struct _disk_entry de
;
1185 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1187 static struct mount_entry
*me
= NULL
;
1191 g_free (me
->me_devname
);
1192 g_free (me
->me_mountdir
);
1193 g_free (me
->me_type
);
1196 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1198 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1201 fd
= open (dir
, O_RDONLY
);
1205 i
= disk_get_entry (fd
, &de
);
1212 switch (de
.disk_type
)
1239 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1242 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1245 me
->me_devname
= g_strdup (dev
);
1246 me
->me_mountdir
= g_strdup (dir
);
1247 me
->me_type
= g_strdup (tp
);
1248 me
->me_dev
= de
.disk_type
;
1252 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1253 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1254 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1255 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1260 #endif /* HAVE_INFOMOUNT_QNX */
1262 /* --------------------------------------------------------------------------------------------- */
1264 #ifdef STAT_READ_FILSYS /* SVR2 */
1266 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1267 interrupted. Return the actual number of bytes read(written), zero for EOF,
1268 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1270 safe_read (int fd
, void *buf
, size_t count
)
1272 /* Work around a bug in Tru64 5.1. Attempting to read more than
1273 INT_MAX bytes fails with errno == EINVAL. See
1274 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1275 When decreasing COUNT, keep it block-aligned. */
1277 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1284 result
= read (fd
, buf
, count
);
1288 else if (IS_EINTR (errno
))
1290 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1291 count
= BUGGY_READ_MAXIMUM
;
1297 /* --------------------------------------------------------------------------------------------- */
1299 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1300 interrupted or if a partial write(read) occurs. Return the number
1301 of bytes transferred.
1302 When writing, set errno if fewer than COUNT bytes are written.
1303 When reading, if fewer than COUNT bytes are read, you must examine
1304 errno to distinguish failure from EOF (errno == 0). */
1307 full_read (int fd
, void *buf
, size_t count
)
1310 char *ptr
= (char *) buf
;
1314 size_t n_rw
= safe_read (fd
, ptr
, count
);
1315 if (n_rw
== (size_t) (-1))
1319 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1330 #endif /* STAT_READ_FILSYS */
1332 /* --------------------------------------------------------------------------------------------- */
1334 #ifdef HAVE_INFOMOUNT
1335 /* Fill in the fields of FSP with information about space usage for
1336 the file system on which FILE resides.
1337 DISK is the device on which FILE is mounted, for space-getting
1338 methods that need to know it.
1339 Return 0 if successful, -1 if not. When returning -1, ensure that
1340 ERRNO is either a system error value, or zero if DISK is NULL
1341 on a system that requires a non-NULL value. */
1343 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1345 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1347 if (statvfs_works ())
1349 struct statvfs vfsd
;
1351 if (statvfs (file
, &vfsd
) < 0)
1354 /* f_frsize isn't guaranteed to be supported. */
1355 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1356 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1357 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1359 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1360 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1361 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1362 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1363 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1364 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1370 #if defined STAT_STATVFS64 /* AIX */
1372 struct statvfs64 fsd
;
1374 if (statvfs64 (file
, &fsd
) < 0)
1377 /* f_frsize isn't guaranteed to be supported. */
1379 fsp
->fsu_blocksize
= fsd
.f_frsize
1380 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1381 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1384 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1388 if (statfs (file
, &fsd
) != 1)
1391 fsp
->fsu_blocksize
= 1024;
1392 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1393 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1394 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1395 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1396 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1397 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1399 #elif defined STAT_READ_FILSYS /* SVR2 */
1401 #define SUPERBOFF (SUPERB * 512)
1413 fd
= open (disk
, O_RDONLY
);
1416 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1417 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1424 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1425 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1426 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1427 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1428 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1429 fsp
->fsu_files
= (fsd
.s_isize
== -1
1430 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1431 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1433 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1437 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1440 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1442 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1446 if (statfs (file
, &fsd
) < 0)
1449 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1451 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1452 Mac OS X < 10.4, FreeBSD < 5.0, \
1453 NetBSD < 3.0, OpenBSD < 4.4 */
1457 if (statfs (file
, &fsd
) < 0)
1460 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1462 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1464 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1465 struct statfs are truncated to 2GB. These conditions detect that
1466 truncation, presumably without botching the 4.1.1 case, in which
1467 the values are not truncated. The correct counts are stored in
1468 undocumented spare fields. */
1469 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1471 fsd
.f_blocks
= fsd
.f_spare
[0];
1472 fsd
.f_bfree
= fsd
.f_spare
[1];
1473 fsd
.f_bavail
= fsd
.f_spare
[2];
1475 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1477 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1481 if (statfs (file
, &fsd
) < 0)
1484 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1486 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1489 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1490 #define f_bavail f_bfree
1495 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1498 /* Empirically, the block counts on most SVR3 and SVR3-derived
1499 systems seem to always be in terms of 512-byte blocks,
1500 no matter what value f_bsize has. */
1501 #if defined _AIX || defined _CRAY
1502 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1504 fsp
->fsu_blocksize
= 512;
1509 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1510 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1511 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1513 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1514 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1515 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1516 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1517 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1518 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1523 (void) disk
; /* avoid argument-unused warning */
1527 #endif /* HAVE_INFOMOUNT */
1529 /* --------------------------------------------------------------------------------------------- */
1530 /*** public functions ****************************************************************************/
1531 /* --------------------------------------------------------------------------------------------- */
1534 free_my_statfs (void)
1536 #ifdef HAVE_INFOMOUNT_LIST
1537 while (mc_mount_list
!= NULL
)
1539 struct mount_entry
*next
;
1541 next
= mc_mount_list
->me_next
;
1542 free_mount_entry (mc_mount_list
);
1543 mc_mount_list
= next
;
1546 mc_mount_list
= NULL
;
1547 #endif /* HAVE_INFOMOUNT_LIST */
1550 /* --------------------------------------------------------------------------------------------- */
1553 init_my_statfs (void)
1555 #ifdef HAVE_INFOMOUNT_LIST
1557 mc_mount_list
= read_file_system_list (1);
1558 #endif /* HAVE_INFOMOUNT_LIST */
1561 /* --------------------------------------------------------------------------------------------- */
1564 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1566 #ifdef HAVE_INFOMOUNT_LIST
1568 struct mount_entry
*entry
= NULL
;
1569 struct mount_entry
*temp
= mc_mount_list
;
1570 struct fs_usage fs_use
;
1574 i
= strlen (temp
->me_mountdir
);
1575 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1576 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == '\0'))
1581 temp
= temp
->me_next
;
1586 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1587 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1589 myfs_stats
->type
= entry
->me_dev
;
1590 myfs_stats
->typename
= entry
->me_type
;
1591 myfs_stats
->mpoint
= entry
->me_mountdir
;
1592 myfs_stats
->device
= entry
->me_devname
;
1594 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1595 fs_use
.fsu_blocksize
) >> 10;
1596 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1597 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1598 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1601 #endif /* HAVE_INFOMOUNT_LIST */
1603 #ifdef HAVE_INFOMOUNT_QNX
1605 ** This is the "other side" of the hack to read_file_system_list() in
1607 ** It's not the most efficient approach, but consumes less memory. It
1608 ** also accomodates QNX's ability to mount filesystems on the fly.
1610 struct mount_entry
*entry
;
1611 struct fs_usage fs_use
;
1613 entry
= read_file_system_list (0, 0);
1616 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1618 myfs_stats
->type
= entry
->me_dev
;
1619 myfs_stats
->typename
= entry
->me_type
;
1620 myfs_stats
->mpoint
= entry
->me_mountdir
;
1621 myfs_stats
->device
= entry
->me_devname
;
1623 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1624 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1625 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1626 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1629 #endif /* HAVE_INFOMOUNT_QNX */
1631 myfs_stats
->type
= 0;
1632 myfs_stats
->mpoint
= "unknown";
1633 myfs_stats
->device
= "unknown";
1634 myfs_stats
->avail
= 0;
1635 myfs_stats
->total
= 0;
1636 myfs_stats
->nfree
= 0;
1637 myfs_stats
->nodes
= 0;
1641 /* --------------------------------------------------------------------------------------------- */