eac0e12baa0ed9f06a853a84985ad0012cca11a1
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
));
814 me
->me_devname
= g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
815 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
816 me
->me_type
= g_strdup (fi
.fsh_name
);
817 me
->me_type_malloced
= 1;
820 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
822 /* Add to the linked list. */
824 mtail
= &me
->me_next
;
828 while (rootdir_list
!= NULL
)
830 struct rootdir_entry
*re
= rootdir_list
;
831 rootdir_list
= re
->next
;
836 #endif /* MOUNTED_FS_STAT_DEV */
838 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
842 struct statfs
*stats
;
844 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
847 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
849 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
853 bufsize
= (1 + numsys
) * sizeof (*stats
);
854 stats
= g_malloc (bufsize
);
855 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
863 for (counter
= 0; counter
< numsys
; counter
++)
865 me
= g_malloc (sizeof (*me
));
866 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
867 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
868 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
869 me
->me_type_malloced
= 1;
870 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
871 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
872 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
874 /* Add to the linked list. */
876 mtail
= &me
->me_next
;
881 #endif /* MOUNTED_GETFSSTAT */
883 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
886 char *table
= "/etc/mnttab";
889 fp
= fopen (table
, "r");
893 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
895 me
= g_malloc (sizeof (*me
));
896 #ifdef GETFSTYP /* SVR3. */
897 me
->me_devname
= g_strdup (mnt
.mt_dev
);
899 me
->me_devname
= g_strconcat ("/dev/", mnt
.mt_dev
, (char *) NULL
);
901 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
902 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
904 me
->me_type_malloced
= 0;
905 #ifdef GETFSTYP /* SVR3. */
909 char typebuf
[FSTYPSZ
];
911 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
912 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
914 me
->me_type
= g_strdup (typebuf
);
915 me
->me_type_malloced
= 1;
919 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
920 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
922 /* Add to the linked list. */
924 mtail
= &me
->me_next
;
929 /* The last fread() call must have failed. */
930 int saved_errno
= errno
;
936 if (fclose (fp
) == EOF
)
939 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
941 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
943 struct mntent
**mnttbl
= getmnttbl (), **ent
;
944 for (ent
= mnttbl
; *ent
; ent
++)
946 me
= g_malloc (sizeof (*me
));
947 me
->me_devname
= g_strdup ((*ent
)->mt_resource
);
948 me
->me_mountdir
= g_strdup ((*ent
)->mt_directory
);
949 me
->me_type
= g_strdup ((*ent
)->mt_fstype
);
950 me
->me_type_malloced
= 1;
951 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
952 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
953 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
955 /* Add to the linked list. */
957 mtail
= &me
->me_next
;
963 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
966 char *table
= MNTTAB
;
971 #if defined F_RDLCK && defined F_SETLKW
972 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
973 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
974 for this file name, we should use their macro name instead.
975 (Why not just lock MNTTAB directly? We don't know.) */
977 #define MNTTAB_LOCK "/etc/.mnttab.lock"
979 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
983 flock
.l_type
= F_RDLCK
;
984 flock
.l_whence
= SEEK_SET
;
987 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
990 int saved_errno
= errno
;
996 else if (errno
!= ENOENT
)
1001 fp
= fopen (table
, "r");
1006 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1008 me
= g_malloc (sizeof (*me
));
1009 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1010 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1011 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1012 me
->me_type_malloced
= 1;
1013 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1014 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1015 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1017 /* Add to the linked list. */
1019 mtail
= &me
->me_next
;
1022 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1025 if (0 <= lockfd
&& close (lockfd
) != 0)
1031 goto free_then_fail
;
1034 #endif /* MOUNTED_GETMNTENT2. */
1036 #ifdef MOUNTED_VMOUNT /* AIX. */
1039 char *entries
, *thisent
;
1044 /* Ask how many bytes to allocate for the mounted file system info. */
1045 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), (struct vmount
*) &bufsize
) != 0)
1047 entries
= g_malloc (bufsize
);
1049 /* Get the list of mounted file systems. */
1050 n_entries
= mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
1053 int saved_errno
= errno
;
1055 errno
= saved_errno
;
1059 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1061 char *options
, *ignore
;
1063 vmp
= (struct vmount
*) thisent
;
1064 me
= g_malloc (sizeof (*me
));
1065 if (vmp
->vmt_flags
& MNT_REMOTE
)
1070 /* Prepend the remote dirname. */
1071 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1072 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1073 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1078 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1080 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1081 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1082 me
->me_type_malloced
= 1;
1083 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1084 ignore
= strstr (options
, "ignore");
1085 me
->me_dummy
= (ignore
1086 && (ignore
== options
|| ignore
[-1] == ',')
1087 && (ignore
[sizeof ("ignore") - 1] == ','
1088 || ignore
[sizeof ("ignore") - 1] == '\0'));
1089 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1091 /* Add to the linked list. */
1093 mtail
= &me
->me_next
;
1097 #endif /* MOUNTED_VMOUNT. */
1100 #ifdef MOUNTED_INTERIX_STATVFS
1102 DIR *dirp
= opendir ("/dev/fs");
1103 char node
[9 + NAME_MAX
];
1106 goto free_then_fail
;
1111 struct dirent entry
;
1112 struct dirent
*result
;
1114 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1117 strcpy (node
, "/dev/fs/");
1118 strcat (node
, entry
.d_name
);
1120 if (statvfs (node
, &dev
) == 0)
1122 me
= g_malloc (sizeof *me
);
1123 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1124 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1125 me
->me_type
= g_strdup (dev
.f_fstypename
);
1126 me
->me_type_malloced
= 1;
1127 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1128 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1129 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1131 /* Add to the linked list. */
1133 mtail
= &me
->me_next
;
1137 #endif /* MOUNTED_INTERIX_STATVFS */
1139 (void) need_fs_type
; /* avoid argument-unused warning */
1146 int saved_errno
= errno
;
1151 me
= mount_list
->me_next
;
1152 g_free (mount_list
->me_devname
);
1153 g_free (mount_list
->me_mountdir
);
1154 if (mount_list
->me_type_malloced
)
1155 g_free (mount_list
->me_type
);
1156 g_free (mount_list
);
1160 errno
= saved_errno
;
1165 #endif /* HAVE_INFOMOUNT_LIST */
1167 /* --------------------------------------------------------------------------------------------- */
1169 #ifdef HAVE_INFOMOUNT_QNX
1171 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1172 ** this via the following code.
1173 ** Note that, as this is based on CWD, it only fills one mount_entry
1174 ** structure. See my_statfs() in utilunix.c for the "other side" of
1178 static struct mount_entry
*
1179 read_file_system_list (int need_fs_type
, int all_fs
)
1181 struct _disk_entry de
;
1184 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1186 static struct mount_entry
*me
= NULL
;
1190 g_free (me
->me_devname
);
1191 g_free (me
->me_mountdir
);
1192 g_free (me
->me_type
);
1195 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1197 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1200 fd
= open (dir
, O_RDONLY
);
1204 i
= disk_get_entry (fd
, &de
);
1211 switch (de
.disk_type
)
1238 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1241 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1244 me
->me_devname
= g_strdup (dev
);
1245 me
->me_mountdir
= g_strdup (dir
);
1246 me
->me_type
= g_strdup (tp
);
1247 me
->me_dev
= de
.disk_type
;
1251 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1252 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1253 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1254 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1259 #endif /* HAVE_INFOMOUNT_QNX */
1261 /* --------------------------------------------------------------------------------------------- */
1263 #ifdef STAT_READ_FILSYS /* SVR2 */
1265 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1266 interrupted. Return the actual number of bytes read(written), zero for EOF,
1267 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1269 safe_read (int fd
, void *buf
, size_t count
)
1271 /* Work around a bug in Tru64 5.1. Attempting to read more than
1272 INT_MAX bytes fails with errno == EINVAL. See
1273 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1274 When decreasing COUNT, keep it block-aligned. */
1276 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1283 result
= read (fd
, buf
, count
);
1287 else if (IS_EINTR (errno
))
1289 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1290 count
= BUGGY_READ_MAXIMUM
;
1296 /* --------------------------------------------------------------------------------------------- */
1298 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1299 interrupted or if a partial write(read) occurs. Return the number
1300 of bytes transferred.
1301 When writing, set errno if fewer than COUNT bytes are written.
1302 When reading, if fewer than COUNT bytes are read, you must examine
1303 errno to distinguish failure from EOF (errno == 0). */
1306 full_read (int fd
, void *buf
, size_t count
)
1309 char *ptr
= (char *) buf
;
1313 size_t n_rw
= safe_read (fd
, ptr
, count
);
1314 if (n_rw
== (size_t) (-1))
1318 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1329 #endif /* STAT_READ_FILSYS */
1331 /* --------------------------------------------------------------------------------------------- */
1333 #ifdef HAVE_INFOMOUNT
1334 /* Fill in the fields of FSP with information about space usage for
1335 the file system on which FILE resides.
1336 DISK is the device on which FILE is mounted, for space-getting
1337 methods that need to know it.
1338 Return 0 if successful, -1 if not. When returning -1, ensure that
1339 ERRNO is either a system error value, or zero if DISK is NULL
1340 on a system that requires a non-NULL value. */
1342 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1344 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1346 if (statvfs_works ())
1348 struct statvfs vfsd
;
1350 if (statvfs (file
, &vfsd
) < 0)
1353 /* f_frsize isn't guaranteed to be supported. */
1354 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1355 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1356 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1358 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1359 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1360 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1361 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1362 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1363 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1369 #if defined STAT_STATVFS64 /* AIX */
1371 struct statvfs64 fsd
;
1373 if (statvfs64 (file
, &fsd
) < 0)
1376 /* f_frsize isn't guaranteed to be supported. */
1378 fsp
->fsu_blocksize
= fsd
.f_frsize
1379 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1380 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1383 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1387 if (statfs (file
, &fsd
) != 1)
1390 fsp
->fsu_blocksize
= 1024;
1391 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1392 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1393 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1394 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1395 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1396 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1398 #elif defined STAT_READ_FILSYS /* SVR2 */
1400 #define SUPERBOFF (SUPERB * 512)
1412 fd
= open (disk
, O_RDONLY
);
1415 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1416 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1423 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1424 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1425 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1426 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1427 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1428 fsp
->fsu_files
= (fsd
.s_isize
== -1
1429 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1430 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1432 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1436 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1439 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1441 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1445 if (statfs (file
, &fsd
) < 0)
1448 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1450 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1451 Mac OS X < 10.4, FreeBSD < 5.0, \
1452 NetBSD < 3.0, OpenBSD < 4.4 */
1456 if (statfs (file
, &fsd
) < 0)
1459 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1461 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1463 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1464 struct statfs are truncated to 2GB. These conditions detect that
1465 truncation, presumably without botching the 4.1.1 case, in which
1466 the values are not truncated. The correct counts are stored in
1467 undocumented spare fields. */
1468 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1470 fsd
.f_blocks
= fsd
.f_spare
[0];
1471 fsd
.f_bfree
= fsd
.f_spare
[1];
1472 fsd
.f_bavail
= fsd
.f_spare
[2];
1474 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1476 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1480 if (statfs (file
, &fsd
) < 0)
1483 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1485 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1488 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1489 #define f_bavail f_bfree
1494 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1497 /* Empirically, the block counts on most SVR3 and SVR3-derived
1498 systems seem to always be in terms of 512-byte blocks,
1499 no matter what value f_bsize has. */
1500 #if defined _AIX || defined _CRAY
1501 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1503 fsp
->fsu_blocksize
= 512;
1508 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1509 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1510 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1512 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1513 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1514 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1515 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1516 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1517 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1522 (void) disk
; /* avoid argument-unused warning */
1526 #endif /* HAVE_INFOMOUNT */
1528 /* --------------------------------------------------------------------------------------------- */
1529 /*** public functions ****************************************************************************/
1530 /* --------------------------------------------------------------------------------------------- */
1533 free_my_statfs (void)
1535 #ifdef HAVE_INFOMOUNT_LIST
1536 while (mc_mount_list
!= NULL
)
1538 struct mount_entry
*next
;
1540 next
= mc_mount_list
->me_next
;
1541 free_mount_entry (mc_mount_list
);
1542 mc_mount_list
= next
;
1545 mc_mount_list
= NULL
;
1546 #endif /* HAVE_INFOMOUNT_LIST */
1549 /* --------------------------------------------------------------------------------------------- */
1552 init_my_statfs (void)
1554 #ifdef HAVE_INFOMOUNT_LIST
1556 mc_mount_list
= read_file_system_list (1);
1557 #endif /* HAVE_INFOMOUNT_LIST */
1560 /* --------------------------------------------------------------------------------------------- */
1563 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1565 #ifdef HAVE_INFOMOUNT_LIST
1567 struct mount_entry
*entry
= NULL
;
1568 struct mount_entry
*temp
= mc_mount_list
;
1569 struct fs_usage fs_use
;
1573 i
= strlen (temp
->me_mountdir
);
1574 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1575 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == '\0'))
1580 temp
= temp
->me_next
;
1585 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1586 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1588 myfs_stats
->type
= entry
->me_dev
;
1589 myfs_stats
->typename
= entry
->me_type
;
1590 myfs_stats
->mpoint
= entry
->me_mountdir
;
1591 myfs_stats
->device
= entry
->me_devname
;
1593 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1594 fs_use
.fsu_blocksize
) >> 10;
1595 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1596 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1597 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1600 #endif /* HAVE_INFOMOUNT_LIST */
1602 #ifdef HAVE_INFOMOUNT_QNX
1604 ** This is the "other side" of the hack to read_file_system_list() in
1606 ** It's not the most efficient approach, but consumes less memory. It
1607 ** also accomodates QNX's ability to mount filesystems on the fly.
1609 struct mount_entry
*entry
;
1610 struct fs_usage fs_use
;
1612 entry
= read_file_system_list (0, 0);
1615 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1617 myfs_stats
->type
= entry
->me_dev
;
1618 myfs_stats
->typename
= entry
->me_type
;
1619 myfs_stats
->mpoint
= entry
->me_mountdir
;
1620 myfs_stats
->device
= entry
->me_devname
;
1622 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1623 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1624 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1625 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1628 #endif /* HAVE_INFOMOUNT_QNX */
1630 myfs_stats
->type
= 0;
1631 myfs_stats
->mpoint
= "unknown";
1632 myfs_stats
->device
= "unknown";
1633 myfs_stats
->avail
= 0;
1634 myfs_stats
->total
= 0;
1635 myfs_stats
->nfree
= 0;
1636 myfs_stats
->nodes
= 0;
1640 /* --------------------------------------------------------------------------------------------- */