2 Return a list of mounted file systems
4 Copyright (C) 1991-2015
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * \brief Source: list of mounted filesystems
33 #include <stdint.h> /* SIZE_MAX */
34 #include <sys/types.h>
38 /* This header needs to be included before sys/mount.h on *BSD */
39 #ifdef HAVE_SYS_PARAM_H
40 #include <sys/param.h>
43 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
44 #include <sys/statvfs.h>
46 /* Don't include backward-compatibility files unless they're needed.
47 Eventually we'd like to remove all this cruft. */
52 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
53 #ifdef HAVE_SYS_UCRED_H
54 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
55 NGROUPS is used as an array dimension in ucred.h */
56 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
58 #ifdef HAVE_SYS_MOUNT_H
59 #include <sys/mount.h>
61 #ifdef HAVE_SYS_FS_TYPES_H
62 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
64 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65 #define FS_TYPE(Ent) ((Ent).f_fstypename)
67 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
69 #endif /* MOUNTED_GETFSSTAT */
70 #endif /* STAT_STATVFS || STAT_STATVFS64 */
75 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
76 #include <sys/fs/s5param.h>
78 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
79 #include <sys/filsys.h> /* SVR2 */
81 #ifdef HAVE_SYS_STATFS_H
82 #include <sys/statfs.h>
84 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
85 #include <sys/dustat.h>
88 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
91 #ifdef _PATH_MOUNTED /* GNU libc */
92 #define MOUNTED _PATH_MOUNTED
94 #ifdef MNT_MNTTAB /* HP-UX. */
95 #define MOUNTED MNT_MNTTAB
97 #ifdef MNTTABNAME /* Dynix. */
98 #define MOUNTED MNTTABNAME
103 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
104 #include <sys/mount.h>
107 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
108 #include <sys/statvfs.h>
111 #ifdef MOUNTED_GETMNT /* Ultrix. */
112 #include <sys/mount.h>
113 #include <sys/fs_types.h>
116 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
121 #ifdef MOUNTED_FREAD /* SVR2. */
125 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
127 #include <sys/fstyp.h>
128 #include <sys/statfs.h>
131 #ifdef MOUNTED_LISTMNTENT
135 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
136 #include <sys/mnttab.h>
139 #ifdef MOUNTED_VMOUNT /* AIX. */
144 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
145 #include <sys/statvfs.h>
150 /* So special that it's not worth putting this in autoconf. */
151 #undef MOUNTED_FREAD_FSTYP
152 #define MOUNTED_GETMNTTBL
155 #ifdef HAVE_SYS_MNTENT_H
156 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
157 #include <sys/mntent.h>
160 #ifdef MOUNTED_PROC_MOUNTINFO
161 /* Use /proc/self/mountinfo instead of /proc/self/mounts (/etc/mtab)
162 * on Linux, if available */
163 #include <libmount/libmount.h>
166 #ifndef HAVE_HASMNTOPT
167 #define hasmntopt(mnt, opt) ((char *) 0)
172 #if defined __sun && defined __SVR4
173 /* Solaris defines hasmntopt(struct mnttab *, char *)
174 while it is otherwise hasmntopt(struct mnttab *, const char *). */
175 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
177 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
180 #define MNT_IGNORE(M) 0
183 #ifdef HAVE_INFOMOUNT_QNX
184 #include <sys/disk.h>
185 #include <sys/fsys.h>
188 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
189 #include <sys/statvfs.h>
192 #include "lib/global.h"
193 #include "lib/strutil.h" /* str_verscmp() */
194 #include "mountlist.h"
196 /*** global variables ****************************************************************************/
198 /*** file scope macro definitions ****************************************************************/
200 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
201 #define HAVE_INFOMOUNT_QNX
204 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
205 #define HAVE_INFOMOUNT
208 /* The results of opendir() in this file are not used with dirfd and fchdir,
209 therefore save some unnecessary work in fchdir.c. */
213 #define ME_DUMMY_0(Fs_name, Fs_type) \
214 (strcmp (Fs_type, "autofs") == 0 \
215 || strcmp (Fs_type, "proc") == 0 \
216 || strcmp (Fs_type, "subfs") == 0 \
217 /* for Linux 2.6/3.x */ \
218 || strcmp (Fs_type, "debugfs") == 0 \
219 || strcmp (Fs_type, "devpts") == 0 \
220 || strcmp (Fs_type, "fusectl") == 0 \
221 || strcmp (Fs_type, "mqueue") == 0 \
222 || strcmp (Fs_type, "rpc_pipefs") == 0 \
223 || strcmp (Fs_type, "sysfs") == 0 \
224 /* FreeBSD, Linux 2.4 */ \
225 || strcmp (Fs_type, "devfs") == 0 \
226 /* for NetBSD 3.0 */ \
227 || strcmp (Fs_type, "kernfs") == 0 \
229 || strcmp (Fs_type, "ignore") == 0)
231 /* Historically, we have marked as "dummy" any file system of type "none",
232 but now that programs like du need to know about bind-mounted directories,
233 we grant an exception to any with "bind" in its list of mount options.
234 I.e., those are *not* dummy entries. */
235 #ifdef MOUNTED_GETMNTENT1
236 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
237 (ME_DUMMY_0 (Fs_name, Fs_type) \
238 || (strcmp (Fs_type, "none") == 0 && !Bind))
240 #define ME_DUMMY(Fs_name, Fs_type) \
241 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
246 #define ME_REMOTE me_remote
247 /* All cygwin mount points include ':' or start with '//'; so it
248 requires a native Windows call to determine remote disks. */
250 me_remote (char const *fs_name
, char const *fs_type
)
254 if (fs_name
[0] && fs_name
[1] == ':')
257 sprintf (drive
, "%c:\\", fs_name
[0]);
258 switch (GetDriveType (drive
))
260 case DRIVE_REMOVABLE
:
271 /* A file system is 'remote' if its Fs_name contains a ':'
272 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//'). */
273 #define ME_REMOTE(Fs_name, Fs_type) \
274 (strchr (Fs_name, ':') != NULL \
275 || ((Fs_name)[0] == '/' \
276 && (Fs_name)[1] == '/' \
277 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
280 /* Many space usage primitives use all 1 bits to denote a value that is
281 not applicable or unknown. Propagate this information by returning
282 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
283 is unsigned and narrower than uintmax_t. */
284 #define PROPAGATE_ALL_ONES(x) \
285 ((sizeof (x) < sizeof (uintmax_t) \
286 && (~ (x) == (sizeof (x) < sizeof (int) \
287 ? - (1 << (sizeof (x) * CHAR_BIT)) \
289 ? UINTMAX_MAX : (uintmax_t) (x))
291 /* Extract the top bit of X as an uintmax_t value. */
292 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
294 /* If a value is negative, many space usage primitives store it into an
295 integer variable by assignment, even if the variable's type is unsigned.
296 So, if a space usage variable X's top bit is set, convert X to the
297 uintmax_t value V such that (- (uintmax_t) V) is the negative of
298 the original value. If X's top bit is clear, just yield X.
299 Use PROPAGATE_TOP_BIT if the original value might be negative;
300 otherwise, use PROPAGATE_ALL_ONES. */
301 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
304 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
305 /* The FRSIZE fallback is not required in this case. */
306 #undef STAT_STATFS2_FRSIZE
308 #include <sys/utsname.h>
309 #include <sys/statfs.h>
310 #define STAT_STATFS2_BSIZE 1
314 #ifdef STAT_READ_FILSYS /* SVR2 */
315 /* Set errno to zero upon EOF. */
316 #define ZERO_BYTE_TRANSFER_ERRNO 0
319 #define IS_EINTR(x) ((x) == EINTR)
321 #define IS_EINTR(x) 0
323 #endif /* STAT_READ_FILSYS */
325 /*** file scope type declarations ****************************************************************/
327 /* A mount table entry. */
330 char *me_devname
; /* Device node name, including "/dev/". */
331 char *me_mountdir
; /* Mount point directory name. */
332 char *me_type
; /* "nfs", "4.2", etc. */
333 dev_t me_dev
; /* Device number of me_mountdir. */
334 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
335 unsigned int me_remote
:1; /* Nonzero for remote fileystems. */
336 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
337 struct mount_entry
*me_next
;
342 uintmax_t fsu_blocksize
; /* Size of a block. */
343 uintmax_t fsu_blocks
; /* Total blocks. */
344 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
345 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
346 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
347 uintmax_t fsu_files
; /* Total file nodes. */
348 uintmax_t fsu_ffree
; /* Free file nodes. */
351 /*** file scope variables ************************************************************************/
353 #ifdef HAVE_INFOMOUNT_LIST
354 static struct mount_entry
*mc_mount_list
= NULL
;
355 #endif /* HAVE_INFOMOUNT_LIST */
357 /*** file scope functions ************************************************************************/
358 /* --------------------------------------------------------------------------------------------- */
361 /* Return true if statvfs works. This is false for statvfs on systems
362 with GNU libc on Linux kernels before 2.6.36, which stats all
363 preceding entries in /proc/mounts; that makes df hang if even one
364 of the corresponding file systems is hard-mounted but not available. */
368 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
371 static int statvfs_works_cache
= -1;
374 if (statvfs_works_cache
< 0)
375 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= str_verscmp (name
.release
, "2.6.36"));
376 return statvfs_works_cache
;
381 /* --------------------------------------------------------------------------------------------- */
383 #ifdef HAVE_INFOMOUNT_LIST
385 free_mount_entry (struct mount_entry
*me
)
389 g_free (me
->me_devname
);
390 g_free (me
->me_mountdir
);
391 if (me
->me_type_malloced
)
392 g_free (me
->me_type
);
396 /* --------------------------------------------------------------------------------------------- */
398 #ifdef MOUNTED_GETMNTINFO
400 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
402 fstype_to_string (short int t
)
407 /* cppcheck-suppress syntaxError */
412 /* cppcheck-suppress syntaxError */
417 /* cppcheck-suppress syntaxError */
422 /* cppcheck-suppress syntaxError */
427 /* cppcheck-suppress syntaxError */
432 /* cppcheck-suppress syntaxError */
437 /* cppcheck-suppress syntaxError */
442 /* cppcheck-suppress syntaxError */
447 /* cppcheck-suppress syntaxError */
452 /* cppcheck-suppress syntaxError */
457 /* cppcheck-suppress syntaxError */
462 /* cppcheck-suppress syntaxError */
467 /* cppcheck-suppress syntaxError */
472 /* cppcheck-suppress syntaxError */
477 /* cppcheck-suppress syntaxError */
482 /* cppcheck-suppress syntaxError */
487 /* cppcheck-suppress syntaxError */
492 /* cppcheck-suppress syntaxError */
497 /* cppcheck-suppress syntaxError */
502 /* cppcheck-suppress syntaxError */
507 /* cppcheck-suppress syntaxError */
515 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
517 /* --------------------------------------------------------------------------------------------- */
520 fsp_to_string (const struct statfs
*fsp
)
522 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
523 return (char *) (fsp
->f_fstypename
);
525 return fstype_to_string (fsp
->f_type
);
528 #endif /* MOUNTED_GETMNTINFO */
530 /* --------------------------------------------------------------------------------------------- */
532 #ifdef MOUNTED_VMOUNT /* AIX. */
534 fstype_to_string (int t
)
538 e
= getvfsbytype (t
);
539 if (!e
|| !e
->vfsent_name
)
542 return e
->vfsent_name
;
544 #endif /* MOUNTED_VMOUNT */
546 /* --------------------------------------------------------------------------------------------- */
548 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
550 /* Return the device number from MOUNT_OPTIONS, if possible.
551 Otherwise return (dev_t) -1. */
553 /* --------------------------------------------------------------------------------------------- */
556 dev_from_mount_options (char const *mount_options
)
558 /* GNU/Linux allows file system implementations to define their own
559 meaning for "dev=" mount options, so don't trust the meaning
562 static char const dev_pattern
[] = ",dev=";
563 char const *devopt
= strstr (mount_options
, dev_pattern
);
567 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
569 unsigned long int dev
;
571 dev
= strtoul (optval
, &optvalend
, 16);
572 if (optval
!= optvalend
573 && (*optvalend
== '\0' || *optvalend
== ',')
574 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
579 (void) mount_options
;
585 /* --------------------------------------------------------------------------------------------- */
587 #if defined _AIX && defined _I386
588 /* AIX PS/2 does not supply statfs. */
591 statfs (char *file
, struct statfs
*fsb
)
596 if (stat (file
, &stats
) != 0)
598 if (dustat (stats
.st_dev
, 0, &fsd
, sizeof (fsd
)))
601 fsb
->f_bsize
= fsd
.du_bsize
;
602 fsb
->f_blocks
= fsd
.du_fsize
- fsd
.du_isize
;
603 fsb
->f_bfree
= fsd
.du_tfree
;
604 fsb
->f_bavail
= fsd
.du_tfree
;
605 fsb
->f_files
= (fsd
.du_isize
- 2) * fsd
.du_inopb
;
606 fsb
->f_ffree
= fsd
.du_tinode
;
607 fsb
->f_fsid
.val
[0] = fsd
.du_site
;
608 fsb
->f_fsid
.val
[1] = fsd
.du_pckno
;
612 #endif /* _AIX && _I386 */
614 /* --------------------------------------------------------------------------------------------- */
616 /* Return a list of the currently mounted file systems, or NULL on error.
617 Add each entry to the tail of the list so that they stay in order.
618 If NEED_FS_TYPE is true, ensure that the file system type fields in
619 the returned list are valid. Otherwise, they might not be. */
621 static struct mount_entry
*
622 read_file_system_list (int need_fs_type
)
624 struct mount_entry
*mount_list
;
625 struct mount_entry
*me
;
626 struct mount_entry
**mtail
= &mount_list
;
628 #ifdef MOUNTED_LISTMNTENT
630 struct tabmntent
*mntlist
, *p
;
631 struct mount_entry
*me
;
633 /* the third and fourth arguments could be used to filter mounts,
634 but Crays doesn't seem to have any mounts that we want to
635 remove. Specifically, automount create normal NFS mounts.
638 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
640 for (p
= mntlist
; p
; p
= p
->next
)
642 struct mntent
*mnt
= p
->ment
;
644 me
= g_malloc (sizeof (*me
));
645 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
646 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
647 me
->me_type
= g_strdup (mnt
->mnt_type
);
648 me
->me_type_malloced
= 1;
649 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
650 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
653 mtail
= &me
->me_next
;
655 freemntlist (mntlist
);
659 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
661 #ifdef MOUNTED_PROC_MOUNTINFO
662 struct libmnt_table
*fstable
= NULL
;
664 fstable
= mnt_new_table_from_file ("/proc/self/mountinfo");
668 struct libmnt_fs
*fs
;
669 struct libmnt_iter
*iter
;
671 iter
= mnt_new_iter (MNT_ITER_FORWARD
);
673 while (iter
&& mnt_table_next_fs (fstable
, iter
, &fs
) == 0)
675 me
= g_malloc (sizeof *me
);
677 me
->me_devname
= g_strdup (mnt_fs_get_source (fs
));
678 me
->me_mountdir
= g_strdup (mnt_fs_get_target (fs
));
679 me
->me_type
= g_strdup (mnt_fs_get_fstype (fs
));
680 me
->me_type_malloced
= 1;
681 me
->me_dev
= mnt_fs_get_devno (fs
);
682 /* Note we don't use mnt_fs_is_pseudofs() or mnt_fs_is_netfs() here
683 as libmount's classification is non-compatible currently.
684 Also we pass "false" for the "Bind" option as that's only
685 significant when the Fs_type is "none" which will not be
686 the case when parsing "/proc/self/mountinfo", and only
687 applies for static /etc/mtab files. */
688 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, FALSE
);
689 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
691 /* Add to the linked list. */
693 mtail
= &me
->me_next
;
696 mnt_free_iter (iter
);
697 mnt_free_table (fstable
);
700 else /* fallback to /proc/self/mounts (/etc/mtab) if anything failed */
701 #endif /* MOUNTED_PROC_MOUNTINFO */
705 const char *table
= MOUNTED
;
707 fp
= setmntent (table
, "r");
711 while ((mnt
= getmntent (fp
)) != NULL
)
715 bind
= hasmntopt (mnt
, "bind") != NULL
;
717 me
= g_malloc (sizeof (*me
));
718 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
719 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
720 me
->me_type
= g_strdup (mnt
->mnt_type
);
721 me
->me_type_malloced
= 1;
722 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
723 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
724 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
726 /* Add to the linked list. */
728 mtail
= &me
->me_next
;
731 if (endmntent (fp
) == 0)
735 #endif /* MOUNTED_GETMNTENT1. */
737 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
742 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
745 for (; entries
-- > 0; fsp
++)
747 char *fs_type
= fsp_to_string (fsp
);
749 me
= g_malloc (sizeof (*me
));
750 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
751 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
752 me
->me_type
= fs_type
;
753 me
->me_type_malloced
= 0;
754 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
755 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
756 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
758 /* Add to the linked list. */
760 mtail
= &me
->me_next
;
763 #endif /* MOUNTED_GETMNTINFO */
765 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
770 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
773 for (; entries
-- > 0; fsp
++)
775 me
= g_malloc (sizeof (*me
));
776 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
777 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
778 me
->me_type
= g_strdup (fsp
->f_fstypename
);
779 me
->me_type_malloced
= 1;
780 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
781 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
782 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
784 /* Add to the linked list. */
786 mtail
= &me
->me_next
;
789 #endif /* MOUNTED_GETMNTINFO2 */
791 #ifdef MOUNTED_GETMNT /* Ultrix. */
800 val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) NULL
);
806 me
= g_malloc (sizeof (*me
));
807 me
->me_devname
= g_strdup (fsd
.fd_req
.devname
);
808 me
->me_mountdir
= g_strdup (fsd
.fd_req
.path
);
809 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
810 me
->me_type_malloced
= 0;
811 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
812 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
813 me
->me_dev
= fsd
.fd_req
.dev
;
815 /* Add to the linked list. */
817 mtail
= &me
->me_next
;
820 #endif /* MOUNTED_GETMNT. */
822 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
824 /* The next_dev() and fs_stat_dev() system calls give the list of
825 all file systems, including the information returned by statvfs()
826 (fs type, total blocks, free blocks etc.), but without the mount
827 point. But on BeOS all file systems except / are mounted in the
828 rootfs, directly under /.
829 The directory name of the mount point is often, but not always,
830 identical to the volume name of the device.
831 We therefore get the list of subdirectories of /, and the list
832 of all file systems, and match the two lists. */
840 struct rootdir_entry
*next
;
842 struct rootdir_entry
*rootdir_list
;
843 struct rootdir_entry
**rootdir_tail
;
848 /* All volumes are mounted in the rootfs, directly under /. */
850 rootdir_tail
= &rootdir_list
;
851 dirp
= opendir (PATH_SEP_STR
);
856 while ((d
= readdir (dirp
)) != NULL
)
861 if (DIR_IS_DOT (d
->d_name
))
864 if (DIR_IS_DOTDOT (d
->d_name
))
865 name
= g_strdup (PATH_SEP_STR
);
867 name
= g_strconcat (PATH_SEP_STR
, d
->d_name
, (char *) NULL
);
869 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
871 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
873 re
->dev
= statbuf
.st_dev
;
874 re
->ino
= statbuf
.st_ino
;
876 /* Add to the linked list. */
878 rootdir_tail
= &re
->next
;
885 *rootdir_tail
= NULL
;
887 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
888 if (fs_stat_dev (dev
, &fi
) >= 0)
890 /* Note: fi.dev == dev. */
891 struct rootdir_entry
*re
;
893 for (re
= rootdir_list
; re
; re
= re
->next
)
894 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
897 me
= g_malloc (sizeof (*me
));
899 g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
900 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
901 me
->me_type
= g_strdup (fi
.fsh_name
);
902 me
->me_type_malloced
= 1;
905 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
907 /* Add to the linked list. */
909 mtail
= &me
->me_next
;
913 while (rootdir_list
!= NULL
)
915 struct rootdir_entry
*re
= rootdir_list
;
916 rootdir_list
= re
->next
;
921 #endif /* MOUNTED_FS_STAT_DEV */
923 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
927 struct statfs
*stats
;
929 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
932 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
934 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
938 bufsize
= (1 + numsys
) * sizeof (*stats
);
939 stats
= g_malloc (bufsize
);
940 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
948 for (counter
= 0; counter
< numsys
; counter
++)
950 me
= g_malloc (sizeof (*me
));
951 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
952 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
953 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
954 me
->me_type_malloced
= 1;
955 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
956 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
957 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
959 /* Add to the linked list. */
961 mtail
= &me
->me_next
;
966 #endif /* MOUNTED_GETFSSTAT */
968 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
971 char *table
= "/etc/mnttab";
974 fp
= fopen (table
, "r");
978 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
980 me
= g_malloc (sizeof (*me
));
981 #ifdef GETFSTYP /* SVR3. */
982 me
->me_devname
= g_strdup (mnt
.mt_dev
);
984 me
->me_devname
= g_strconcat ("/dev/", mnt
.mt_dev
, (char *) NULL
);
986 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
987 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
989 me
->me_type_malloced
= 0;
990 #ifdef GETFSTYP /* SVR3. */
994 char typebuf
[FSTYPSZ
];
996 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
997 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
999 me
->me_type
= g_strdup (typebuf
);
1000 me
->me_type_malloced
= 1;
1004 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1005 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1007 /* Add to the linked list. */
1009 mtail
= &me
->me_next
;
1014 /* The last fread() call must have failed. */
1015 int saved_errno
= errno
;
1017 errno
= saved_errno
;
1018 goto free_then_fail
;
1021 if (fclose (fp
) == EOF
)
1022 goto free_then_fail
;
1024 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
1026 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
1028 struct mntent
**mnttbl
= getmnttbl (), **ent
;
1029 for (ent
= mnttbl
; *ent
; ent
++)
1031 me
= g_malloc (sizeof (*me
));
1032 me
->me_devname
= g_strdup ((*ent
)->mt_resource
);
1033 me
->me_mountdir
= g_strdup ((*ent
)->mt_directory
);
1034 me
->me_type
= g_strdup ((*ent
)->mt_fstype
);
1035 me
->me_type_malloced
= 1;
1036 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1037 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1038 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1040 /* Add to the linked list. */
1042 mtail
= &me
->me_next
;
1048 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
1051 char *table
= MNTTAB
;
1056 #if defined F_RDLCK && defined F_SETLKW
1057 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
1058 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
1059 for this file name, we should use their macro name instead.
1060 (Why not just lock MNTTAB directly? We don't know.) */
1062 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1064 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
1069 flock
.l_type
= F_RDLCK
;
1070 flock
.l_whence
= SEEK_SET
;
1073 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
1076 int saved_errno
= errno
;
1078 errno
= saved_errno
;
1082 else if (errno
!= ENOENT
)
1087 fp
= fopen (table
, "r");
1092 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1094 me
= g_malloc (sizeof (*me
));
1095 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1096 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1097 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1098 me
->me_type_malloced
= 1;
1099 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1100 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1101 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1103 /* Add to the linked list. */
1105 mtail
= &me
->me_next
;
1108 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1111 if (lockfd
>= 0 && close (lockfd
) != 0)
1117 goto free_then_fail
;
1120 #endif /* MOUNTED_GETMNTENT2. */
1122 #ifdef MOUNTED_VMOUNT /* AIX. */
1125 char *entries
, *thisent
;
1130 /* Ask how many bytes to allocate for the mounted file system info. */
1131 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), (struct vmount
*) &bufsize
) != 0)
1133 entries
= g_malloc (bufsize
);
1135 /* Get the list of mounted file systems. */
1136 n_entries
= mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
1139 int saved_errno
= errno
;
1141 errno
= saved_errno
;
1145 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1147 char *options
, *ignore
;
1149 vmp
= (struct vmount
*) thisent
;
1150 me
= g_malloc (sizeof (*me
));
1151 if (vmp
->vmt_flags
& MNT_REMOTE
)
1156 /* Prepend the remote dirname. */
1157 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1158 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1159 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1164 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1166 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1167 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1168 me
->me_type_malloced
= 1;
1169 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1170 ignore
= strstr (options
, "ignore");
1171 me
->me_dummy
= (ignore
1172 && (ignore
== options
|| ignore
[-1] == ',')
1173 && (ignore
[sizeof ("ignore") - 1] == ','
1174 || ignore
[sizeof ("ignore") - 1] == '\0'));
1175 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1177 /* Add to the linked list. */
1179 mtail
= &me
->me_next
;
1183 #endif /* MOUNTED_VMOUNT. */
1186 #ifdef MOUNTED_INTERIX_STATVFS
1188 DIR *dirp
= opendir ("/dev/fs");
1189 char node
[9 + NAME_MAX
];
1192 goto free_then_fail
;
1197 struct dirent entry
;
1198 struct dirent
*result
;
1200 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1203 strcpy (node
, "/dev/fs/");
1204 strcat (node
, entry
.d_name
);
1206 if (statvfs (node
, &dev
) == 0)
1208 me
= g_malloc (sizeof *me
);
1209 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1210 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1211 me
->me_type
= g_strdup (dev
.f_fstypename
);
1212 me
->me_type_malloced
= 1;
1213 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1214 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1215 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1217 /* Add to the linked list. */
1219 mtail
= &me
->me_next
;
1224 #endif /* MOUNTED_INTERIX_STATVFS */
1226 (void) need_fs_type
; /* avoid argument-unused warning */
1233 int saved_errno
= errno
;
1238 me
= mount_list
->me_next
;
1239 g_free (mount_list
->me_devname
);
1240 g_free (mount_list
->me_mountdir
);
1241 if (mount_list
->me_type_malloced
)
1242 g_free (mount_list
->me_type
);
1243 g_free (mount_list
);
1247 errno
= saved_errno
;
1252 #endif /* HAVE_INFOMOUNT_LIST */
1254 /* --------------------------------------------------------------------------------------------- */
1256 #ifdef HAVE_INFOMOUNT_QNX
1258 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1259 ** this via the following code.
1260 ** Note that, as this is based on CWD, it only fills one mount_entry
1261 ** structure. See my_statfs() in utilunix.c for the "other side" of
1265 static struct mount_entry
*
1266 read_file_system_list (int need_fs_type
, int all_fs
)
1268 struct _disk_entry de
;
1271 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1273 static struct mount_entry
*me
= NULL
;
1277 g_free (me
->me_devname
);
1278 g_free (me
->me_mountdir
);
1279 g_free (me
->me_type
);
1282 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1284 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1287 fd
= open (dir
, O_RDONLY
);
1291 i
= disk_get_entry (fd
, &de
);
1298 switch (de
.disk_type
)
1325 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1328 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1331 me
->me_devname
= g_strdup (dev
);
1332 me
->me_mountdir
= g_strdup (dir
);
1333 me
->me_type
= g_strdup (tp
);
1334 me
->me_dev
= de
.disk_type
;
1338 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1339 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1340 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1341 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1346 #endif /* HAVE_INFOMOUNT_QNX */
1348 /* --------------------------------------------------------------------------------------------- */
1350 #ifdef STAT_READ_FILSYS /* SVR2 */
1352 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1353 interrupted. Return the actual number of bytes read(written), zero for EOF,
1354 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1356 safe_read (int fd
, void *buf
, size_t count
)
1358 /* Work around a bug in Tru64 5.1. Attempting to read more than
1359 INT_MAX bytes fails with errno == EINVAL. See
1360 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1361 When decreasing COUNT, keep it block-aligned. */
1363 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1370 result
= read (fd
, buf
, count
);
1374 else if (IS_EINTR (errno
))
1376 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1377 count
= BUGGY_READ_MAXIMUM
;
1383 /* --------------------------------------------------------------------------------------------- */
1385 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1386 interrupted or if a partial write(read) occurs. Return the number
1387 of bytes transferred.
1388 When writing, set errno if fewer than COUNT bytes are written.
1389 When reading, if fewer than COUNT bytes are read, you must examine
1390 errno to distinguish failure from EOF (errno == 0). */
1393 full_read (int fd
, void *buf
, size_t count
)
1396 char *ptr
= (char *) buf
;
1400 size_t n_rw
= safe_read (fd
, ptr
, count
);
1401 if (n_rw
== (size_t) (-1))
1405 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1416 #endif /* STAT_READ_FILSYS */
1418 /* --------------------------------------------------------------------------------------------- */
1420 #ifdef HAVE_INFOMOUNT
1421 /* Fill in the fields of FSP with information about space usage for
1422 the file system on which FILE resides.
1423 DISK is the device on which FILE is mounted, for space-getting
1424 methods that need to know it.
1425 Return 0 if successful, -1 if not. When returning -1, ensure that
1426 ERRNO is either a system error value, or zero if DISK is NULL
1427 on a system that requires a non-NULL value. */
1429 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1431 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1433 if (statvfs_works ())
1435 struct statvfs vfsd
;
1437 if (statvfs (file
, &vfsd
) < 0)
1440 /* f_frsize isn't guaranteed to be supported. */
1441 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1442 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1443 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1445 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1446 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1447 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1448 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1449 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1450 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1456 #if defined STAT_STATVFS64 /* AIX */
1458 struct statvfs64 fsd
;
1460 if (statvfs64 (file
, &fsd
) < 0)
1463 /* f_frsize isn't guaranteed to be supported. */
1465 fsp
->fsu_blocksize
= fsd
.f_frsize
1466 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1467 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1470 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1474 if (statfs (file
, &fsd
) != 1)
1477 fsp
->fsu_blocksize
= 1024;
1478 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1479 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1480 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1481 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1482 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1483 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1485 #elif defined STAT_READ_FILSYS /* SVR2 */
1487 #define SUPERBOFF (SUPERB * 512)
1499 fd
= open (disk
, O_RDONLY
);
1502 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1503 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1510 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1511 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1512 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1513 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1514 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1515 fsp
->fsu_files
= (fsd
.s_isize
== -1
1516 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1517 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1519 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1523 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1526 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1528 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1532 if (statfs (file
, &fsd
) < 0)
1535 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1537 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1538 Mac OS X < 10.4, FreeBSD < 5.0, \
1539 NetBSD < 3.0, OpenBSD < 4.4 */
1543 if (statfs (file
, &fsd
) < 0)
1546 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1548 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1550 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1551 struct statfs are truncated to 2GB. These conditions detect that
1552 truncation, presumably without botching the 4.1.1 case, in which
1553 the values are not truncated. The correct counts are stored in
1554 undocumented spare fields. */
1555 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1557 fsd
.f_blocks
= fsd
.f_spare
[0];
1558 fsd
.f_bfree
= fsd
.f_spare
[1];
1559 fsd
.f_bavail
= fsd
.f_spare
[2];
1561 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1563 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1567 if (statfs (file
, &fsd
) < 0)
1570 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1572 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1575 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1576 #define f_bavail f_bfree
1581 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1584 /* Empirically, the block counts on most SVR3 and SVR3-derived
1585 systems seem to always be in terms of 512-byte blocks,
1586 no matter what value f_bsize has. */
1587 #if defined _AIX || defined _CRAY
1588 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1590 fsp
->fsu_blocksize
= 512;
1595 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1596 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1597 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1599 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1600 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1601 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1602 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1603 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1604 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1609 (void) disk
; /* avoid argument-unused warning */
1613 #endif /* HAVE_INFOMOUNT */
1615 /* --------------------------------------------------------------------------------------------- */
1616 /*** public functions ****************************************************************************/
1617 /* --------------------------------------------------------------------------------------------- */
1620 free_my_statfs (void)
1622 #ifdef HAVE_INFOMOUNT_LIST
1623 while (mc_mount_list
!= NULL
)
1625 struct mount_entry
*next
;
1627 next
= mc_mount_list
->me_next
;
1628 free_mount_entry (mc_mount_list
);
1629 mc_mount_list
= next
;
1632 mc_mount_list
= NULL
;
1633 #endif /* HAVE_INFOMOUNT_LIST */
1636 /* --------------------------------------------------------------------------------------------- */
1639 init_my_statfs (void)
1641 #ifdef HAVE_INFOMOUNT_LIST
1643 mc_mount_list
= read_file_system_list (1);
1644 #endif /* HAVE_INFOMOUNT_LIST */
1647 /* --------------------------------------------------------------------------------------------- */
1650 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1652 #ifdef HAVE_INFOMOUNT_LIST
1654 struct mount_entry
*entry
= NULL
;
1655 struct mount_entry
*temp
= mc_mount_list
;
1656 struct fs_usage fs_use
;
1662 i
= strlen (temp
->me_mountdir
);
1663 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1664 if (entry
== NULL
|| IS_PATH_SEP (path
[i
]) || path
[i
] == '\0')
1669 temp
= temp
->me_next
;
1674 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1675 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1677 myfs_stats
->type
= entry
->me_dev
;
1678 myfs_stats
->typename
= entry
->me_type
;
1679 myfs_stats
->mpoint
= entry
->me_mountdir
;
1680 myfs_stats
->device
= entry
->me_devname
;
1682 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1683 fs_use
.fsu_blocksize
) >> 10;
1684 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1685 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1686 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1689 #endif /* HAVE_INFOMOUNT_LIST */
1691 #ifdef HAVE_INFOMOUNT_QNX
1693 ** This is the "other side" of the hack to read_file_system_list() in
1695 ** It's not the most efficient approach, but consumes less memory. It
1696 ** also accommodates QNX's ability to mount filesystems on the fly.
1698 struct mount_entry
*entry
;
1699 struct fs_usage fs_use
;
1701 entry
= read_file_system_list (0, 0);
1704 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1706 myfs_stats
->type
= entry
->me_dev
;
1707 myfs_stats
->typename
= entry
->me_type
;
1708 myfs_stats
->mpoint
= entry
->me_mountdir
;
1709 myfs_stats
->device
= entry
->me_devname
;
1711 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1712 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1713 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1714 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1717 #endif /* HAVE_INFOMOUNT_QNX */
1719 myfs_stats
->type
= 0;
1720 myfs_stats
->mpoint
= "unknown";
1721 myfs_stats
->device
= "unknown";
1722 myfs_stats
->avail
= 0;
1723 myfs_stats
->total
= 0;
1724 myfs_stats
->nfree
= 0;
1725 myfs_stats
->nodes
= 0;
1729 /* --------------------------------------------------------------------------------------------- */