2 Return a list of mounted file systems
4 Copyright (C) 1991-2016
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. */
90 #include <sys/types.h>
92 #ifdef _PATH_MOUNTED /* GNU libc */
93 #define MOUNTED _PATH_MOUNTED
95 #ifdef MNT_MNTTAB /* HP-UX. */
96 #define MOUNTED MNT_MNTTAB
98 #ifdef MNTTABNAME /* Dynix. */
99 #define MOUNTED MNTTABNAME
104 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
105 #include <sys/mount.h>
108 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
109 #include <sys/statvfs.h>
112 #ifdef MOUNTED_GETMNT /* Ultrix. */
113 #include <sys/mount.h>
114 #include <sys/fs_types.h>
117 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
122 #ifdef MOUNTED_FREAD /* SVR2. */
126 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
128 #include <sys/fstyp.h>
129 #include <sys/statfs.h>
132 #ifdef MOUNTED_LISTMNTENT
136 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
137 #include <sys/mnttab.h>
140 #ifdef MOUNTED_VMOUNT /* AIX. */
145 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
146 #include <sys/statvfs.h>
151 /* So special that it's not worth putting this in autoconf. */
152 #undef MOUNTED_FREAD_FSTYP
153 #define MOUNTED_GETMNTTBL
156 #ifdef HAVE_SYS_MNTENT_H
157 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
158 #include <sys/mntent.h>
161 #ifndef HAVE_HASMNTOPT
162 #define hasmntopt(mnt, opt) ((char *) 0)
167 #if defined __sun && defined __SVR4
168 /* Solaris defines hasmntopt(struct mnttab *, char *)
169 while it is otherwise hasmntopt(struct mnttab *, const char *). */
170 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
172 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
175 #define MNT_IGNORE(M) 0
178 #ifdef HAVE_INFOMOUNT_QNX
179 #include <sys/disk.h>
180 #include <sys/fsys.h>
183 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
184 #include <sys/statvfs.h>
187 #include "lib/global.h"
188 #include "lib/strutil.h" /* str_verscmp() */
189 #include "mountlist.h"
191 /*** global variables ****************************************************************************/
193 /*** file scope macro definitions ****************************************************************/
195 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
196 #define HAVE_INFOMOUNT_QNX
199 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
200 #define HAVE_INFOMOUNT
203 /* The results of opendir() in this file are not used with dirfd and fchdir,
204 therefore save some unnecessary work in fchdir.c. */
208 #define ME_DUMMY_0(Fs_name, Fs_type) \
209 (strcmp (Fs_type, "autofs") == 0 \
210 || strcmp (Fs_type, "proc") == 0 \
211 || strcmp (Fs_type, "subfs") == 0 \
212 /* for Linux 2.6/3.x */ \
213 || strcmp (Fs_type, "debugfs") == 0 \
214 || strcmp (Fs_type, "devpts") == 0 \
215 || strcmp (Fs_type, "fusectl") == 0 \
216 || strcmp (Fs_type, "mqueue") == 0 \
217 || strcmp (Fs_type, "rpc_pipefs") == 0 \
218 || strcmp (Fs_type, "sysfs") == 0 \
219 /* FreeBSD, Linux 2.4 */ \
220 || strcmp (Fs_type, "devfs") == 0 \
221 /* for NetBSD 3.0 */ \
222 || strcmp (Fs_type, "kernfs") == 0 \
224 || strcmp (Fs_type, "ignore") == 0)
226 /* Historically, we have marked as "dummy" any file system of type "none",
227 but now that programs like du need to know about bind-mounted directories,
228 we grant an exception to any with "bind" in its list of mount options.
229 I.e., those are *not* dummy entries. */
230 #ifdef MOUNTED_GETMNTENT1
231 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
232 (ME_DUMMY_0 (Fs_name, Fs_type) \
233 || (strcmp (Fs_type, "none") == 0 && !Bind))
235 #define ME_DUMMY(Fs_name, Fs_type) \
236 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
241 #define ME_REMOTE me_remote
242 /* All cygwin mount points include ':' or start with '//'; so it
243 requires a native Windows call to determine remote disks. */
245 me_remote (char const *fs_name
, char const *fs_type
)
249 if (fs_name
[0] && fs_name
[1] == ':')
252 sprintf (drive
, "%c:\\", fs_name
[0]);
253 switch (GetDriveType (drive
))
255 case DRIVE_REMOVABLE
:
266 /* A file system is 'remote' if its Fs_name contains a ':'
267 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//'). */
268 #define ME_REMOTE(Fs_name, Fs_type) \
269 (strchr (Fs_name, ':') != NULL \
270 || ((Fs_name)[0] == '/' \
271 && (Fs_name)[1] == '/' \
272 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
275 /* Many space usage primitives use all 1 bits to denote a value that is
276 not applicable or unknown. Propagate this information by returning
277 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
278 is unsigned and narrower than uintmax_t. */
279 #define PROPAGATE_ALL_ONES(x) \
280 ((sizeof (x) < sizeof (uintmax_t) \
281 && (~ (x) == (sizeof (x) < sizeof (int) \
282 ? - (1 << (sizeof (x) * CHAR_BIT)) \
284 ? UINTMAX_MAX : (uintmax_t) (x))
286 /* Extract the top bit of X as an uintmax_t value. */
287 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
289 /* If a value is negative, many space usage primitives store it into an
290 integer variable by assignment, even if the variable's type is unsigned.
291 So, if a space usage variable X's top bit is set, convert X to the
292 uintmax_t value V such that (- (uintmax_t) V) is the negative of
293 the original value. If X's top bit is clear, just yield X.
294 Use PROPAGATE_TOP_BIT if the original value might be negative;
295 otherwise, use PROPAGATE_ALL_ONES. */
296 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
299 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
300 /* The FRSIZE fallback is not required in this case. */
301 #undef STAT_STATFS2_FRSIZE
303 #include <sys/utsname.h>
304 #include <sys/statfs.h>
305 #define STAT_STATFS2_BSIZE 1
309 #ifdef STAT_READ_FILSYS /* SVR2 */
310 /* Set errno to zero upon EOF. */
311 #define ZERO_BYTE_TRANSFER_ERRNO 0
314 #define IS_EINTR(x) ((x) == EINTR)
316 #define IS_EINTR(x) 0
318 #endif /* STAT_READ_FILSYS */
320 /*** file scope type declarations ****************************************************************/
322 /* A mount table entry. */
325 char *me_devname
; /* Device node name, including "/dev/". */
326 char *me_mountdir
; /* Mount point directory name. */
327 char *me_mntroot
; /* Directory on filesystem of device used
328 as root for the (bind) mount. */
329 char *me_type
; /* "nfs", "4.2", etc. */
330 dev_t me_dev
; /* Device number of me_mountdir. */
331 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
332 unsigned int me_remote
:1; /* Nonzero for remote fileystems. */
333 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
338 uintmax_t fsu_blocksize
; /* Size of a block. */
339 uintmax_t fsu_blocks
; /* Total blocks. */
340 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
341 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
342 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
343 uintmax_t fsu_files
; /* Total file nodes. */
344 uintmax_t fsu_ffree
; /* Free file nodes. */
347 /*** file scope variables ************************************************************************/
349 #ifdef HAVE_INFOMOUNT_LIST
350 static GSList
*mc_mount_list
= NULL
;
351 #endif /* HAVE_INFOMOUNT_LIST */
353 /*** file scope functions ************************************************************************/
354 /* --------------------------------------------------------------------------------------------- */
357 /* Return true if statvfs works. This is false for statvfs on systems
358 with GNU libc on Linux kernels before 2.6.36, which stats all
359 preceding entries in /proc/mounts; that makes df hang if even one
360 of the corresponding file systems is hard-mounted but not available. */
364 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
367 static int statvfs_works_cache
= -1;
370 if (statvfs_works_cache
< 0)
371 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= str_verscmp (name
.release
, "2.6.36"));
372 return statvfs_works_cache
;
377 /* --------------------------------------------------------------------------------------------- */
379 #ifdef HAVE_INFOMOUNT_LIST
381 free_mount_entry (struct mount_entry
*me
)
385 g_free (me
->me_devname
);
386 g_free (me
->me_mountdir
);
387 g_free (me
->me_mntroot
);
388 if (me
->me_type_malloced
)
389 g_free (me
->me_type
);
393 /* --------------------------------------------------------------------------------------------- */
395 #ifdef MOUNTED_GETMNTINFO
397 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
399 fstype_to_string (short int t
)
404 /* cppcheck-suppress syntaxError */
409 /* cppcheck-suppress syntaxError */
414 /* cppcheck-suppress syntaxError */
419 /* cppcheck-suppress syntaxError */
424 /* cppcheck-suppress syntaxError */
429 /* cppcheck-suppress syntaxError */
434 /* cppcheck-suppress syntaxError */
439 /* cppcheck-suppress syntaxError */
444 /* cppcheck-suppress syntaxError */
449 /* cppcheck-suppress syntaxError */
454 /* cppcheck-suppress syntaxError */
459 /* cppcheck-suppress syntaxError */
464 /* cppcheck-suppress syntaxError */
469 /* cppcheck-suppress syntaxError */
474 /* cppcheck-suppress syntaxError */
479 /* cppcheck-suppress syntaxError */
484 /* cppcheck-suppress syntaxError */
489 /* cppcheck-suppress syntaxError */
494 /* cppcheck-suppress syntaxError */
499 /* cppcheck-suppress syntaxError */
504 /* cppcheck-suppress syntaxError */
512 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
514 /* --------------------------------------------------------------------------------------------- */
517 fsp_to_string (const struct statfs
*fsp
)
519 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
520 return (char *) (fsp
->f_fstypename
);
522 return fstype_to_string (fsp
->f_type
);
525 #endif /* MOUNTED_GETMNTINFO */
527 /* --------------------------------------------------------------------------------------------- */
529 #ifdef MOUNTED_VMOUNT /* AIX. */
531 fstype_to_string (int t
)
535 e
= getvfsbytype (t
);
536 if (!e
|| !e
->vfsent_name
)
539 return e
->vfsent_name
;
541 #endif /* MOUNTED_VMOUNT */
543 /* --------------------------------------------------------------------------------------------- */
545 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
547 /* Return the device number from MOUNT_OPTIONS, if possible.
548 Otherwise return (dev_t) -1. */
550 /* --------------------------------------------------------------------------------------------- */
553 dev_from_mount_options (char const *mount_options
)
555 /* GNU/Linux allows file system implementations to define their own
556 meaning for "dev=" mount options, so don't trust the meaning
559 static char const dev_pattern
[] = ",dev=";
560 char const *devopt
= strstr (mount_options
, dev_pattern
);
564 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
566 unsigned long int dev
;
568 dev
= strtoul (optval
, &optvalend
, 16);
569 if (optval
!= optvalend
570 && (*optvalend
== '\0' || *optvalend
== ',')
571 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
576 (void) mount_options
;
582 /* --------------------------------------------------------------------------------------------- */
584 #if defined _AIX && defined _I386
585 /* AIX PS/2 does not supply statfs. */
588 statfs (char *file
, struct statfs
*fsb
)
593 if (stat (file
, &stats
) != 0)
595 if (dustat (stats
.st_dev
, 0, &fsd
, sizeof (fsd
)))
598 fsb
->f_bsize
= fsd
.du_bsize
;
599 fsb
->f_blocks
= fsd
.du_fsize
- fsd
.du_isize
;
600 fsb
->f_bfree
= fsd
.du_tfree
;
601 fsb
->f_bavail
= fsd
.du_tfree
;
602 fsb
->f_files
= (fsd
.du_isize
- 2) * fsd
.du_inopb
;
603 fsb
->f_ffree
= fsd
.du_tinode
;
604 fsb
->f_fsid
.val
[0] = fsd
.du_site
;
605 fsb
->f_fsid
.val
[1] = fsd
.du_pckno
;
609 #endif /* _AIX && _I386 */
611 /* --------------------------------------------------------------------------------------------- */
613 #if defined MOUNTED_GETMNTENT1 && defined __linux__
615 /* Unescape the paths in mount tables.
616 STR is updated in place. */
618 unescape_tab (char *str
)
623 len
= strlen (str
) + 1;
625 for (i
= 0; i
< len
; i
++)
627 if (str
[i
] == '\\' && (i
+ 4 < len
)
628 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
629 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7' && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
631 str
[j
++] = (str
[i
+ 1] - '0') * 64 + (str
[i
+ 2] - '0') * 8 + (str
[i
+ 3] - '0');
640 /* --------------------------------------------------------------------------------------------- */
642 /* Return a list of the currently mounted file systems, or NULL on error.
643 Add each entry to the tail of the list so that they stay in order.
644 If NEED_FS_TYPE is true, ensure that the file system type fields in
645 the returned list are valid. Otherwise, they might not be. */
648 read_file_system_list (int need_fs_type
)
650 GSList
*mount_list
= NULL
;
651 struct mount_entry
*me
;
653 #ifdef MOUNTED_LISTMNTENT
655 struct tabmntent
*mntlist
, *p
;
657 /* the third and fourth arguments could be used to filter mounts,
658 but Crays doesn't seem to have any mounts that we want to
659 remove. Specifically, automount create normal NFS mounts.
662 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
664 for (p
= mntlist
; p
; p
= p
->next
)
666 struct mntent
*mnt
= p
->ment
;
668 me
= g_malloc (sizeof (*me
));
669 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
670 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
671 me
->me_mntroot
= NULL
;
672 me
->me_type
= g_strdup (mnt
->mnt_type
);
673 me
->me_type_malloced
= 1;
674 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
675 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
678 mount_list
= g_slist_prepend (mount_list
, me
);
680 freemntlist (mntlist
);
684 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
689 /* Try parsing mountinfo first, as that make device IDs available.
690 Note we could use libmount routines to simplify this parsing a little
691 (and that code is in previous versions of this function), however
692 libmount depends on libselinux which pulls in many dependencies. */
693 char const *mountinfo
= "/proc/self/mountinfo";
695 fp
= fopen (mountinfo
, "r");
701 while (getline (&line
, &buf_size
, fp
) != -1)
703 unsigned int devmaj
, devmin
;
704 int target_s
, target_e
, type_s
, type_e
;
705 int source_s
, source_e
, mntroot_s
, mntroot_e
;
710 rc
= sscanf (line
, "%*u " /* id - discarded */
711 "%*u " /* parent - discarded */
712 "%u:%u " /* dev major:minor */
713 "%n%*s%n " /* mountroot */
714 "%n%*s%n" /* target, start and end */
715 "%c", /* more data... */
716 &devmaj
, &devmin
, &mntroot_s
, &mntroot_e
, &target_s
, &target_e
, &test
);
718 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
721 /* skip optional fields, terminated by " - " */
722 dash
= strstr (line
+ target_e
, " - ");
726 rc
= sscanf (dash
, " - " /* */
727 "%n%*s%n " /* FS type, start and end */
728 "%n%*s%n " /* source, start and end */
729 "%c", /* more data... */
730 &type_s
, &type_e
, &source_s
, &source_e
, &test
);
731 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
734 /* manipulate the sub-strings in place. */
735 line
[mntroot_e
] = '\0';
736 line
[target_e
] = '\0';
738 dash
[source_e
] = '\0';
739 unescape_tab (dash
+ source_s
);
740 unescape_tab (line
+ target_s
);
741 unescape_tab (line
+ mntroot_s
);
743 me
= g_malloc (sizeof *me
);
745 me
->me_devname
= g_strdup (dash
+ source_s
);
746 me
->me_mountdir
= g_strdup (line
+ target_s
);
747 me
->me_mntroot
= g_strdup (line
+ mntroot_s
);
748 me
->me_type
= g_strdup (dash
+ type_s
);
749 me
->me_type_malloced
= 1;
750 me
->me_dev
= makedev (devmaj
, devmin
);
751 /* we pass "false" for the "Bind" option as that's only
752 significant when the Fs_type is "none" which will not be
753 the case when parsing "/proc/self/mountinfo", and only
754 applies for static /etc/mtab files. */
755 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, FALSE
);
756 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
758 mount_list
= g_slist_prepend (mount_list
, me
);
763 if (ferror (fp
) != 0)
765 int saved_errno
= errno
;
772 if (fclose (fp
) == EOF
)
775 else /* fallback to /proc/self/mounts (/etc/mtab). */
776 #endif /* __linux __ */
779 const char *table
= MOUNTED
;
781 fp
= setmntent (table
, "r");
785 while ((mnt
= getmntent (fp
)) != NULL
)
789 bind
= hasmntopt (mnt
, "bind") != NULL
;
791 me
= g_malloc (sizeof (*me
));
792 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
793 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
794 me
->me_mntroot
= NULL
;
795 me
->me_type
= g_strdup (mnt
->mnt_type
);
796 me
->me_type_malloced
= 1;
797 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
798 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
799 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
801 mount_list
= g_slist_prepend (mount_list
, me
);
804 if (endmntent (fp
) == 0)
808 #endif /* MOUNTED_GETMNTENT1. */
810 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
815 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
818 for (; entries
-- > 0; fsp
++)
820 char *fs_type
= fsp_to_string (fsp
);
822 me
= g_malloc (sizeof (*me
));
823 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
824 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
825 me
->me_mntroot
= NULL
;
826 me
->me_type
= fs_type
;
827 me
->me_type_malloced
= 0;
828 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
829 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
830 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
832 mount_list
= g_slist_prepend (mount_list
, me
);
835 #endif /* MOUNTED_GETMNTINFO */
837 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
842 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
845 for (; entries
-- > 0; fsp
++)
847 me
= g_malloc (sizeof (*me
));
848 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
849 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
850 me
->me_mntroot
= NULL
;
851 me
->me_type
= g_strdup (fsp
->f_fstypename
);
852 me
->me_type_malloced
= 1;
853 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
854 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
855 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
857 mount_list
= g_slist_prepend (mount_list
, me
);
860 #endif /* MOUNTED_GETMNTINFO2 */
862 #ifdef MOUNTED_GETMNT /* Ultrix. */
871 val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) NULL
);
877 me
= g_malloc (sizeof (*me
));
878 me
->me_devname
= g_strdup (fsd
.fd_req
.devname
);
879 me
->me_mountdir
= g_strdup (fsd
.fd_req
.path
);
880 me
->me_mntroot
= NULL
;
881 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
882 me
->me_type_malloced
= 0;
883 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
884 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
885 me
->me_dev
= fsd
.fd_req
.dev
;
887 mount_list
= g_slist_prepend (mount_list
, me
);
890 #endif /* MOUNTED_GETMNT. */
892 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
894 /* The next_dev() and fs_stat_dev() system calls give the list of
895 all file systems, including the information returned by statvfs()
896 (fs type, total blocks, free blocks etc.), but without the mount
897 point. But on BeOS all file systems except / are mounted in the
898 rootfs, directly under /.
899 The directory name of the mount point is often, but not always,
900 identical to the volume name of the device.
901 We therefore get the list of subdirectories of /, and the list
902 of all file systems, and match the two lists. */
910 struct rootdir_entry
*next
;
912 struct rootdir_entry
*rootdir_list
;
913 struct rootdir_entry
**rootdir_tail
;
918 /* All volumes are mounted in the rootfs, directly under /. */
920 rootdir_tail
= &rootdir_list
;
921 dirp
= opendir (PATH_SEP_STR
);
926 while ((d
= readdir (dirp
)) != NULL
)
931 if (DIR_IS_DOT (d
->d_name
))
934 if (DIR_IS_DOTDOT (d
->d_name
))
935 name
= g_strdup (PATH_SEP_STR
);
937 name
= g_strconcat (PATH_SEP_STR
, d
->d_name
, (char *) NULL
);
939 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
941 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
943 re
->dev
= statbuf
.st_dev
;
944 re
->ino
= statbuf
.st_ino
;
946 /* Add to the linked list. */
948 rootdir_tail
= &re
->next
;
955 *rootdir_tail
= NULL
;
957 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
958 if (fs_stat_dev (dev
, &fi
) >= 0)
960 /* Note: fi.dev == dev. */
961 struct rootdir_entry
*re
;
963 for (re
= rootdir_list
; re
; re
= re
->next
)
964 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
967 me
= g_malloc (sizeof (*me
));
969 g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
970 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
971 me
->me_mntroot
= NULL
;
972 me
->me_type
= g_strdup (fi
.fsh_name
);
973 me
->me_type_malloced
= 1;
976 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
978 mount_list
= g_slist_prepend (mount_list
, me
);
981 while (rootdir_list
!= NULL
)
983 struct rootdir_entry
*re
= rootdir_list
;
985 rootdir_list
= re
->next
;
990 #endif /* MOUNTED_FS_STAT_DEV */
992 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
996 struct statfs
*stats
;
998 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
1001 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
1003 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
1004 exit (EXIT_FAILURE
);
1007 bufsize
= (1 + numsys
) * sizeof (*stats
);
1008 stats
= g_malloc (bufsize
);
1009 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
1017 for (counter
= 0; counter
< numsys
; counter
++)
1019 me
= g_malloc (sizeof (*me
));
1020 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
1021 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
1022 me
->me_mntroot
= NULL
;
1023 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
1024 me
->me_type_malloced
= 1;
1025 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1026 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1027 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1029 mount_list
= g_slist_prepend (mount_list
, me
);
1034 #endif /* MOUNTED_GETFSSTAT */
1036 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
1039 char *table
= "/etc/mnttab";
1042 fp
= fopen (table
, "r");
1046 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
1048 me
= g_malloc (sizeof (*me
));
1049 #ifdef GETFSTYP /* SVR3. */
1050 me
->me_devname
= g_strdup (mnt
.mt_dev
);
1052 me
->me_devname
= g_strconcat ("/dev/", mnt
.mt_dev
, (char *) NULL
);
1054 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
1055 me
->me_mntroot
= NULL
;
1056 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1058 me
->me_type_malloced
= 0;
1059 #ifdef GETFSTYP /* SVR3. */
1063 char typebuf
[FSTYPSZ
];
1065 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
1066 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
1068 me
->me_type
= g_strdup (typebuf
);
1069 me
->me_type_malloced
= 1;
1073 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1074 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1076 mount_list
= g_slist_prepend (mount_list
, me
);
1081 /* The last fread() call must have failed. */
1082 int saved_errno
= errno
;
1085 errno
= saved_errno
;
1086 goto free_then_fail
;
1089 if (fclose (fp
) == EOF
)
1090 goto free_then_fail
;
1092 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
1094 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
1096 struct mntent
**mnttbl
= getmnttbl (), **ent
;
1098 for (ent
= mnttbl
; *ent
; ent
++)
1100 me
= g_malloc (sizeof (*me
));
1101 me
->me_devname
= g_strdup ((*ent
)->mt_resource
);
1102 me
->me_mountdir
= g_strdup ((*ent
)->mt_directory
);
1103 me
->me_mntroot
= NULL
;
1104 me
->me_type
= g_strdup ((*ent
)->mt_fstype
);
1105 me
->me_type_malloced
= 1;
1106 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1107 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1108 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1110 mount_list
= g_slist_prepend (mount_list
, me
);
1116 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
1119 char *table
= MNTTAB
;
1124 #if defined F_RDLCK && defined F_SETLKW
1125 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
1126 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
1127 for this file name, we should use their macro name instead.
1128 (Why not just lock MNTTAB directly? We don't know.) */
1130 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1132 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
1137 flock
.l_type
= F_RDLCK
;
1138 flock
.l_whence
= SEEK_SET
;
1141 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
1144 int saved_errno
= errno
;
1146 errno
= saved_errno
;
1150 else if (errno
!= ENOENT
)
1155 fp
= fopen (table
, "r");
1160 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1162 me
= g_malloc (sizeof (*me
));
1163 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1164 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1165 me
->me_mntroot
= NULL
;
1166 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1167 me
->me_type_malloced
= 1;
1168 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1169 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1170 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1172 mount_list
= g_slist_prepend (mount_list
, me
);
1175 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1178 if (lockfd
>= 0 && close (lockfd
) != 0)
1184 goto free_then_fail
;
1187 #endif /* MOUNTED_GETMNTENT2. */
1189 #ifdef MOUNTED_VMOUNT /* AIX. */
1198 /* Ask how many bytes to allocate for the mounted file system info. */
1200 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), entries
) != 0)
1202 entries
= g_malloc (bufsize
);
1204 /* Get the list of mounted file systems. */
1205 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1208 int saved_errno
= errno
;
1211 errno
= saved_errno
;
1215 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1217 char *options
, *ignore
;
1219 vmp
= (struct vmount
*) thisent
;
1220 me
= g_malloc (sizeof (*me
));
1221 if (vmp
->vmt_flags
& MNT_REMOTE
)
1226 /* Prepend the remote dirname. */
1227 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1228 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1229 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1234 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1236 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1237 me
->me_mntroot
= NULL
;
1238 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1239 me
->me_type_malloced
= 1;
1240 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1241 ignore
= strstr (options
, "ignore");
1242 me
->me_dummy
= (ignore
1243 && (ignore
== options
|| ignore
[-1] == ',')
1244 && (ignore
[sizeof ("ignore") - 1] == ','
1245 || ignore
[sizeof ("ignore") - 1] == '\0'));
1246 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1248 mount_list
= g_slist_prepend (mount_list
, me
);
1252 #endif /* MOUNTED_VMOUNT. */
1254 #ifdef MOUNTED_INTERIX_STATVFS
1256 DIR *dirp
= opendir ("/dev/fs");
1257 char node
[9 + NAME_MAX
];
1260 goto free_then_fail
;
1265 struct dirent entry
;
1266 struct dirent
*result
;
1268 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1271 strcpy (node
, "/dev/fs/");
1272 strcat (node
, entry
.d_name
);
1274 if (statvfs (node
, &dev
) == 0)
1276 me
= g_malloc (sizeof *me
);
1277 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1278 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1279 me
->me_mntroot
= NULL
;
1280 me
->me_type
= g_strdup (dev
.f_fstypename
);
1281 me
->me_type_malloced
= 1;
1282 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1283 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1284 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1286 mount_list
= g_slist_prepend (mount_list
, me
);
1291 #endif /* MOUNTED_INTERIX_STATVFS */
1293 (void) need_fs_type
; /* avoid argument-unused warning */
1295 return g_slist_reverse (mount_list
);
1299 int saved_errno
= errno
;
1301 g_slist_free_full (mount_list
, (GDestroyNotify
) free_mount_entry
);
1303 errno
= saved_errno
;
1307 #endif /* HAVE_INFOMOUNT_LIST */
1309 /* --------------------------------------------------------------------------------------------- */
1311 #ifdef HAVE_INFOMOUNT_QNX
1313 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1314 ** this via the following code.
1315 ** Note that, as this is based on CWD, it only fills one mount_entry
1316 ** structure. See my_statfs() in utilunix.c for the "other side" of
1321 read_file_system_list (int need_fs_type
, int all_fs
)
1323 struct _disk_entry de
;
1326 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1327 struct mount_entry
*me
= NULL
;
1328 static GSList
*list
= NULL
;
1332 me
= (struct mount_entry
*) list
->data
;
1334 g_free (me
->me_devname
);
1335 g_free (me
->me_mountdir
);
1336 g_free (me
->me_mntroot
);
1337 g_free (me
->me_type
);
1341 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1342 list
= g_slist_prepend (list
, me
);
1345 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1348 fd
= open (dir
, O_RDONLY
);
1352 i
= disk_get_entry (fd
, &de
);
1359 switch (de
.disk_type
)
1386 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1389 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1392 me
->me_devname
= g_strdup (dev
);
1393 me
->me_mountdir
= g_strdup (dir
);
1394 me
->me_mntroot
= NULL
;
1395 me
->me_type
= g_strdup (tp
);
1396 me
->me_dev
= de
.disk_type
;
1400 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1401 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1402 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1403 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1408 #endif /* HAVE_INFOMOUNT_QNX */
1410 /* --------------------------------------------------------------------------------------------- */
1412 #ifdef STAT_READ_FILSYS /* SVR2 */
1414 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1415 interrupted. Return the actual number of bytes read(written), zero for EOF,
1416 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1418 safe_read (int fd
, void *buf
, size_t count
)
1420 /* Work around a bug in Tru64 5.1. Attempting to read more than
1421 INT_MAX bytes fails with errno == EINVAL. See
1422 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1423 When decreasing COUNT, keep it block-aligned. */
1425 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1432 result
= read (fd
, buf
, count
);
1436 else if (IS_EINTR (errno
))
1438 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1439 count
= BUGGY_READ_MAXIMUM
;
1445 /* --------------------------------------------------------------------------------------------- */
1447 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1448 interrupted or if a partial write(read) occurs. Return the number
1449 of bytes transferred.
1450 When writing, set errno if fewer than COUNT bytes are written.
1451 When reading, if fewer than COUNT bytes are read, you must examine
1452 errno to distinguish failure from EOF (errno == 0). */
1455 full_read (int fd
, void *buf
, size_t count
)
1458 char *ptr
= (char *) buf
;
1462 size_t n_rw
= safe_read (fd
, ptr
, count
);
1463 if (n_rw
== (size_t) (-1))
1467 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1478 #endif /* STAT_READ_FILSYS */
1480 /* --------------------------------------------------------------------------------------------- */
1482 #ifdef HAVE_INFOMOUNT
1483 /* Fill in the fields of FSP with information about space usage for
1484 the file system on which FILE resides.
1485 DISK is the device on which FILE is mounted, for space-getting
1486 methods that need to know it.
1487 Return 0 if successful, -1 if not. When returning -1, ensure that
1488 ERRNO is either a system error value, or zero if DISK is NULL
1489 on a system that requires a non-NULL value. */
1491 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1493 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1495 if (statvfs_works ())
1497 struct statvfs vfsd
;
1499 if (statvfs (file
, &vfsd
) < 0)
1502 /* f_frsize isn't guaranteed to be supported. */
1503 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1504 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1505 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1507 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1508 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1509 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1510 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1511 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1512 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1518 #if defined STAT_STATVFS64 /* AIX */
1520 struct statvfs64 fsd
;
1522 if (statvfs64 (file
, &fsd
) < 0)
1525 /* f_frsize isn't guaranteed to be supported. */
1527 fsp
->fsu_blocksize
= fsd
.f_frsize
1528 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1529 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1532 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1536 if (statfs (file
, &fsd
) != 1)
1539 fsp
->fsu_blocksize
= 1024;
1540 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1541 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1542 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1543 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1544 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1545 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1547 #elif defined STAT_READ_FILSYS /* SVR2 */
1549 #define SUPERBOFF (SUPERB * 512)
1561 fd
= open (disk
, O_RDONLY
);
1564 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1565 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1572 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1573 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1574 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1575 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1576 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1577 fsp
->fsu_files
= (fsd
.s_isize
== -1
1578 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1579 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1581 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1585 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1588 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1590 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1594 if (statfs (file
, &fsd
) < 0)
1597 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1599 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1600 Mac OS X < 10.4, FreeBSD < 5.0, \
1601 NetBSD < 3.0, OpenBSD < 4.4 */
1605 if (statfs (file
, &fsd
) < 0)
1608 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1610 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1612 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1613 struct statfs are truncated to 2GB. These conditions detect that
1614 truncation, presumably without botching the 4.1.1 case, in which
1615 the values are not truncated. The correct counts are stored in
1616 undocumented spare fields. */
1617 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1619 fsd
.f_blocks
= fsd
.f_spare
[0];
1620 fsd
.f_bfree
= fsd
.f_spare
[1];
1621 fsd
.f_bavail
= fsd
.f_spare
[2];
1623 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1625 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1629 if (statfs (file
, &fsd
) < 0)
1632 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1634 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1637 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1638 #define f_bavail f_bfree
1643 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1646 /* Empirically, the block counts on most SVR3 and SVR3-derived
1647 systems seem to always be in terms of 512-byte blocks,
1648 no matter what value f_bsize has. */
1649 #if defined _AIX || defined _CRAY
1650 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1652 fsp
->fsu_blocksize
= 512;
1657 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1658 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1659 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1661 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1662 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1663 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1664 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1665 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1666 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1671 (void) disk
; /* avoid argument-unused warning */
1675 #endif /* HAVE_INFOMOUNT */
1677 /* --------------------------------------------------------------------------------------------- */
1678 /*** public functions ****************************************************************************/
1679 /* --------------------------------------------------------------------------------------------- */
1682 free_my_statfs (void)
1684 #ifdef HAVE_INFOMOUNT_LIST
1685 g_slist_free_full (mc_mount_list
, (GDestroyNotify
) free_mount_entry
);
1686 mc_mount_list
= NULL
;
1687 #endif /* HAVE_INFOMOUNT_LIST */
1690 /* --------------------------------------------------------------------------------------------- */
1693 init_my_statfs (void)
1695 #ifdef HAVE_INFOMOUNT_LIST
1697 mc_mount_list
= read_file_system_list (1);
1698 #endif /* HAVE_INFOMOUNT_LIST */
1701 /* --------------------------------------------------------------------------------------------- */
1704 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1706 #ifdef HAVE_INFOMOUNT_LIST
1708 struct mount_entry
*entry
= NULL
;
1710 struct fs_usage fs_use
;
1712 for (temp
= mc_mount_list
; temp
!= NULL
; temp
= g_slist_next (temp
))
1714 struct mount_entry
*me
;
1717 me
= (struct mount_entry
*) temp
->data
;
1718 i
= strlen (me
->me_mountdir
);
1719 if (i
> len
&& (strncmp (path
, me
->me_mountdir
, i
) == 0) &&
1720 (entry
== NULL
|| IS_PATH_SEP (path
[i
]) || path
[i
] == '\0'))
1729 memset (&fs_use
, 0, sizeof (fs_use
));
1730 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1732 myfs_stats
->type
= entry
->me_dev
;
1733 myfs_stats
->typename
= entry
->me_type
;
1734 myfs_stats
->mpoint
= entry
->me_mountdir
;
1735 myfs_stats
->mroot
= entry
->me_mntroot
;
1736 myfs_stats
->device
= entry
->me_devname
;
1738 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1739 fs_use
.fsu_blocksize
) >> 10;
1740 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1741 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1742 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1745 #endif /* HAVE_INFOMOUNT_LIST */
1747 #ifdef HAVE_INFOMOUNT_QNX
1749 ** This is the "other side" of the hack to read_file_system_list() in
1751 ** It's not the most efficient approach, but consumes less memory. It
1752 ** also accommodates QNX's ability to mount filesystems on the fly.
1754 struct mount_entry
*entry
;
1755 struct fs_usage fs_use
;
1757 entry
= read_file_system_list (0, 0);
1760 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1762 myfs_stats
->type
= entry
->me_dev
;
1763 myfs_stats
->typename
= entry
->me_type
;
1764 myfs_stats
->mpoint
= entry
->me_mountdir
;
1765 myfs_stats
->mroot
= entry
->me_mntroot
;
1766 myfs_stats
->device
= entry
->me_devname
;
1768 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1769 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1770 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1771 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1774 #endif /* HAVE_INFOMOUNT_QNX */
1776 myfs_stats
->type
= 0;
1777 myfs_stats
->mpoint
= "unknown";
1778 myfs_stats
->device
= "unknown";
1779 myfs_stats
->avail
= 0;
1780 myfs_stats
->total
= 0;
1781 myfs_stats
->nfree
= 0;
1782 myfs_stats
->nodes
= 0;
1786 /* --------------------------------------------------------------------------------------------- */