2 Return a list of mounted file systems
4 Copyright (C) 1991-2018
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, also (obsolete) Apple Darwin 1.3 */
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 #ifdef HAVE_SYS_STATFS_H
79 #include <sys/statfs.h>
82 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
83 also (obsolete) 4.3BSD, SunOS, Dynix */
85 #include <sys/types.h>
87 #ifdef _PATH_MOUNTED /* GNU libc */
88 #define MOUNTED _PATH_MOUNTED
90 #ifdef MNT_MNTTAB /* HP-UX. */
91 #define MOUNTED MNT_MNTTAB
93 #ifdef MNTTABNAME /* Dynix. */
94 #define MOUNTED MNTTABNAME
99 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
100 #include <sys/mount.h>
103 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
104 #include <sys/statvfs.h>
107 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
108 #include <sys/mount.h>
109 #include <sys/fs_types.h>
112 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
117 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
119 #include <sys/fstyp.h>
120 #include <sys/statfs.h>
123 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
127 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
128 #include <sys/mnttab.h>
131 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
132 #include <sys/mnttab.h>
135 #ifdef MOUNTED_VMOUNT /* AIX */
140 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
141 #include <sys/statvfs.h>
145 #ifdef HAVE_SYS_MNTENT_H
146 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
147 #include <sys/mntent.h>
150 #ifndef HAVE_HASMNTOPT
151 #define hasmntopt(mnt, opt) ((char *) 0)
156 #if defined __sun && defined __SVR4
157 /* Solaris defines hasmntopt(struct mnttab *, char *)
158 while it is otherwise hasmntopt(struct mnttab *, const char *). */
159 #define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
161 #define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
164 #define MNT_IGNORE(M) 0
167 #ifdef HAVE_INFOMOUNT_QNX
168 #include <sys/disk.h>
169 #include <sys/fsys.h>
172 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
173 #include <sys/statvfs.h>
176 #include "lib/global.h"
177 #include "lib/strutil.h" /* str_verscmp() */
178 #include "lib/unixcompat.h" /* makedev */
179 #include "mountlist.h"
181 /*** global variables ****************************************************************************/
183 /*** file scope macro definitions ****************************************************************/
185 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
186 #define HAVE_INFOMOUNT_QNX
189 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
190 #define HAVE_INFOMOUNT
193 /* The results of opendir() in this file are not used with dirfd and fchdir,
194 therefore save some unnecessary work in fchdir.c. */
198 #define ME_DUMMY_0(Fs_name, Fs_type) \
199 (strcmp (Fs_type, "autofs") == 0 \
200 || strcmp (Fs_type, "proc") == 0 \
201 || strcmp (Fs_type, "subfs") == 0 \
202 /* for Linux 2.6/3.x */ \
203 || strcmp (Fs_type, "debugfs") == 0 \
204 || strcmp (Fs_type, "devpts") == 0 \
205 || strcmp (Fs_type, "fusectl") == 0 \
206 || strcmp (Fs_type, "mqueue") == 0 \
207 || strcmp (Fs_type, "rpc_pipefs") == 0 \
208 || strcmp (Fs_type, "sysfs") == 0 \
209 /* FreeBSD, Linux 2.4 */ \
210 || strcmp (Fs_type, "devfs") == 0 \
211 /* for NetBSD 3.0 */ \
212 || strcmp (Fs_type, "kernfs") == 0 \
214 || strcmp (Fs_type, "ignore") == 0)
216 /* Historically, we have marked as "dummy" any file system of type "none",
217 but now that programs like du need to know about bind-mounted directories,
218 we grant an exception to any with "bind" in its list of mount options.
219 I.e., those are *not* dummy entries. */
220 #ifdef MOUNTED_GETMNTENT1
221 #define ME_DUMMY(Fs_name, Fs_type, Bind) \
222 (ME_DUMMY_0 (Fs_name, Fs_type) \
223 || (strcmp (Fs_type, "none") == 0 && !Bind))
225 #define ME_DUMMY(Fs_name, Fs_type) \
226 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
231 #define ME_REMOTE me_remote
232 /* All cygwin mount points include ':' or start with '//'; so it
233 requires a native Windows call to determine remote disks. */
235 me_remote (char const *fs_name
, char const *fs_type
)
239 if (fs_name
[0] && fs_name
[1] == ':')
242 sprintf (drive
, "%c:\\", fs_name
[0]);
243 switch (GetDriveType (drive
))
245 case DRIVE_REMOVABLE
:
256 /* A file system is 'remote' if its Fs_name contains a ':'
257 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
258 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
259 #define ME_REMOTE(Fs_name, Fs_type) \
260 (strchr (Fs_name, ':') != NULL \
261 || ((Fs_name)[0] == '/' \
262 && (Fs_name)[1] == '/' \
263 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)) \
264 || (strcmp("-hosts", Fs_name) == 0))
267 /* Many space usage primitives use all 1 bits to denote a value that is
268 not applicable or unknown. Propagate this information by returning
269 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
270 is unsigned and narrower than uintmax_t. */
271 #define PROPAGATE_ALL_ONES(x) \
272 ((sizeof (x) < sizeof (uintmax_t) \
273 && (~ (x) == (sizeof (x) < sizeof (int) \
274 ? - (1 << (sizeof (x) * CHAR_BIT)) \
276 ? UINTMAX_MAX : (uintmax_t) (x))
278 /* Extract the top bit of X as an uintmax_t value. */
279 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
281 /* If a value is negative, many space usage primitives store it into an
282 integer variable by assignment, even if the variable's type is unsigned.
283 So, if a space usage variable X's top bit is set, convert X to the
284 uintmax_t value V such that (- (uintmax_t) V) is the negative of
285 the original value. If X's top bit is clear, just yield X.
286 Use PROPAGATE_TOP_BIT if the original value might be negative;
287 otherwise, use PROPAGATE_ALL_ONES. */
288 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
291 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
292 /* The FRSIZE fallback is not required in this case. */
293 #undef STAT_STATFS2_FRSIZE
295 #include <sys/utsname.h>
296 #include <sys/statfs.h>
297 #define STAT_STATFS2_BSIZE 1
301 /*** file scope type declarations ****************************************************************/
303 /* A mount table entry. */
306 char *me_devname
; /* Device node name, including "/dev/". */
307 char *me_mountdir
; /* Mount point directory name. */
308 char *me_mntroot
; /* Directory on filesystem of device used
309 as root for the (bind) mount. */
310 char *me_type
; /* "nfs", "4.2", etc. */
311 dev_t me_dev
; /* Device number of me_mountdir. */
312 unsigned int me_dummy
:1; /* Nonzero for dummy file systems. */
313 unsigned int me_remote
:1; /* Nonzero for remote fileystems. */
314 unsigned int me_type_malloced
:1; /* Nonzero if me_type was malloced. */
319 uintmax_t fsu_blocksize
; /* Size of a block. */
320 uintmax_t fsu_blocks
; /* Total blocks. */
321 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
322 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
323 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
324 uintmax_t fsu_files
; /* Total file nodes. */
325 uintmax_t fsu_ffree
; /* Free file nodes. */
328 /*** file scope variables ************************************************************************/
330 #ifdef HAVE_INFOMOUNT_LIST
331 static GSList
*mc_mount_list
= NULL
;
332 #endif /* HAVE_INFOMOUNT_LIST */
334 /*** file scope functions ************************************************************************/
335 /* --------------------------------------------------------------------------------------------- */
338 /* Return true if statvfs works. This is false for statvfs on systems
339 with GNU libc on Linux kernels before 2.6.36, which stats all
340 preceding entries in /proc/mounts; that makes df hang if even one
341 of the corresponding file systems is hard-mounted but not available. */
345 #if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
348 static int statvfs_works_cache
= -1;
351 if (statvfs_works_cache
< 0)
352 statvfs_works_cache
= (uname (&name
) == 0 && 0 <= str_verscmp (name
.release
, "2.6.36"));
353 return statvfs_works_cache
;
358 /* --------------------------------------------------------------------------------------------- */
360 #ifdef HAVE_INFOMOUNT_LIST
362 free_mount_entry (struct mount_entry
*me
)
366 g_free (me
->me_devname
);
367 g_free (me
->me_mountdir
);
368 g_free (me
->me_mntroot
);
369 if (me
->me_type_malloced
)
370 g_free (me
->me_type
);
374 /* --------------------------------------------------------------------------------------------- */
376 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
378 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
380 fstype_to_string (short int t
)
385 /* cppcheck-suppress syntaxError */
390 /* cppcheck-suppress syntaxError */
395 /* cppcheck-suppress syntaxError */
400 /* cppcheck-suppress syntaxError */
405 /* cppcheck-suppress syntaxError */
410 /* cppcheck-suppress syntaxError */
415 /* cppcheck-suppress syntaxError */
420 /* cppcheck-suppress syntaxError */
425 /* cppcheck-suppress syntaxError */
430 /* cppcheck-suppress syntaxError */
435 /* cppcheck-suppress syntaxError */
440 /* cppcheck-suppress syntaxError */
445 /* cppcheck-suppress syntaxError */
450 /* cppcheck-suppress syntaxError */
455 /* cppcheck-suppress syntaxError */
460 /* cppcheck-suppress syntaxError */
465 /* cppcheck-suppress syntaxError */
470 /* cppcheck-suppress syntaxError */
475 /* cppcheck-suppress syntaxError */
480 /* cppcheck-suppress syntaxError */
485 /* cppcheck-suppress syntaxError */
493 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
495 /* --------------------------------------------------------------------------------------------- */
498 fsp_to_string (const struct statfs
*fsp
)
500 #ifdef HAVE_STRUCT_STATFS_F_FSTYPENAME
501 return (char *) (fsp
->f_fstypename
);
503 return fstype_to_string (fsp
->f_type
);
506 #endif /* MOUNTED_GETMNTINFO */
508 /* --------------------------------------------------------------------------------------------- */
510 #ifdef MOUNTED_VMOUNT /* AIX */
512 fstype_to_string (int t
)
516 e
= getvfsbytype (t
);
517 if (!e
|| !e
->vfsent_name
)
520 return e
->vfsent_name
;
522 #endif /* MOUNTED_VMOUNT */
524 /* --------------------------------------------------------------------------------------------- */
526 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
528 /* Return the device number from MOUNT_OPTIONS, if possible.
529 Otherwise return (dev_t) -1. */
531 /* --------------------------------------------------------------------------------------------- */
534 dev_from_mount_options (char const *mount_options
)
536 /* GNU/Linux allows file system implementations to define their own
537 meaning for "dev=" mount options, so don't trust the meaning
540 static char const dev_pattern
[] = ",dev=";
541 char const *devopt
= strstr (mount_options
, dev_pattern
);
545 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
547 unsigned long int dev
;
549 dev
= strtoul (optval
, &optvalend
, 16);
550 if (optval
!= optvalend
551 && (*optvalend
== '\0' || *optvalend
== ',')
552 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
557 (void) mount_options
;
563 /* --------------------------------------------------------------------------------------------- */
565 #if defined MOUNTED_GETMNTENT1 && defined __linux__ /* GNU/Linux, Android */
567 /* Unescape the paths in mount tables.
568 STR is updated in place. */
570 unescape_tab (char *str
)
575 len
= strlen (str
) + 1;
577 for (i
= 0; i
< len
; i
++)
579 if (str
[i
] == '\\' && (i
+ 4 < len
)
580 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
581 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7' && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
583 str
[j
++] = (str
[i
+ 1] - '0') * 64 + (str
[i
+ 2] - '0') * 8 + (str
[i
+ 3] - '0');
592 /* --------------------------------------------------------------------------------------------- */
594 /* Return a list of the currently mounted file systems, or NULL on error.
595 Add each entry to the tail of the list so that they stay in order. */
598 read_file_system_list (void)
600 GSList
*mount_list
= NULL
;
601 struct mount_entry
*me
;
603 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
605 struct tabmntent
*mntlist
, *p
;
607 /* the third and fourth arguments could be used to filter mounts,
608 but Crays doesn't seem to have any mounts that we want to
609 remove. Specifically, automount create normal NFS mounts.
612 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
614 for (p
= mntlist
; p
; p
= p
->next
)
616 struct mntent
*mnt
= p
->ment
;
618 me
= g_malloc (sizeof (*me
));
619 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
620 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
621 me
->me_mntroot
= NULL
;
622 me
->me_type
= g_strdup (mnt
->mnt_type
);
623 me
->me_type_malloced
= 1;
624 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
625 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
628 mount_list
= g_slist_prepend (mount_list
, me
);
630 freemntlist (mntlist
);
634 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
635 also (obsolete) 4.3BSD, SunOS, Dynix */
640 /* Try parsing mountinfo first, as that make device IDs available.
641 Note we could use libmount routines to simplify this parsing a little
642 (and that code is in previous versions of this function), however
643 libmount depends on libselinux which pulls in many dependencies. */
644 char const *mountinfo
= "/proc/self/mountinfo";
646 fp
= fopen (mountinfo
, "r");
652 while (getline (&line
, &buf_size
, fp
) != -1)
654 unsigned int devmaj
, devmin
;
655 int target_s
, target_e
, type_s
, type_e
;
656 int source_s
, source_e
, mntroot_s
, mntroot_e
;
661 rc
= sscanf (line
, "%*u " /* id - discarded */
662 "%*u " /* parent - discarded */
663 "%u:%u " /* dev major:minor */
664 "%n%*s%n " /* mountroot */
665 "%n%*s%n" /* target, start and end */
666 "%c", /* more data... */
667 &devmaj
, &devmin
, &mntroot_s
, &mntroot_e
, &target_s
, &target_e
, &test
);
669 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
672 /* skip optional fields, terminated by " - " */
673 dash
= strstr (line
+ target_e
, " - ");
677 rc
= sscanf (dash
, " - " /* */
678 "%n%*s%n " /* FS type, start and end */
679 "%n%*s%n " /* source, start and end */
680 "%c", /* more data... */
681 &type_s
, &type_e
, &source_s
, &source_e
, &test
);
682 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
685 /* manipulate the sub-strings in place. */
686 line
[mntroot_e
] = '\0';
687 line
[target_e
] = '\0';
689 dash
[source_e
] = '\0';
690 unescape_tab (dash
+ source_s
);
691 unescape_tab (line
+ target_s
);
692 unescape_tab (line
+ mntroot_s
);
694 me
= g_malloc (sizeof *me
);
696 me
->me_devname
= g_strdup (dash
+ source_s
);
697 me
->me_mountdir
= g_strdup (line
+ target_s
);
698 me
->me_mntroot
= g_strdup (line
+ mntroot_s
);
699 me
->me_type
= g_strdup (dash
+ type_s
);
700 me
->me_type_malloced
= 1;
701 me
->me_dev
= makedev (devmaj
, devmin
);
702 /* we pass "false" for the "Bind" option as that's only
703 significant when the Fs_type is "none" which will not be
704 the case when parsing "/proc/self/mountinfo", and only
705 applies for static /etc/mtab files. */
706 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, FALSE
);
707 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
709 mount_list
= g_slist_prepend (mount_list
, me
);
714 if (ferror (fp
) != 0)
716 int saved_errno
= errno
;
723 if (fclose (fp
) == EOF
)
726 else /* fallback to /proc/self/mounts (/etc/mtab). */
727 #endif /* __linux __ */
730 const char *table
= MOUNTED
;
732 fp
= setmntent (table
, "r");
736 while ((mnt
= getmntent (fp
)) != NULL
)
740 bind
= hasmntopt (mnt
, "bind") != NULL
;
742 me
= g_malloc (sizeof (*me
));
743 me
->me_devname
= g_strdup (mnt
->mnt_fsname
);
744 me
->me_mountdir
= g_strdup (mnt
->mnt_dir
);
745 me
->me_mntroot
= NULL
;
746 me
->me_type
= g_strdup (mnt
->mnt_type
);
747 me
->me_type_malloced
= 1;
748 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
749 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
750 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
752 mount_list
= g_slist_prepend (mount_list
, me
);
755 if (endmntent (fp
) == 0)
759 #endif /* MOUNTED_GETMNTENT1. */
761 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
766 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
769 for (; entries
-- > 0; fsp
++)
771 char *fs_type
= fsp_to_string (fsp
);
773 me
= g_malloc (sizeof (*me
));
774 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
775 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
776 me
->me_mntroot
= NULL
;
777 me
->me_type
= fs_type
;
778 me
->me_type_malloced
= 0;
779 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
780 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
781 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
783 mount_list
= g_slist_prepend (mount_list
, me
);
786 #endif /* MOUNTED_GETMNTINFO */
788 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
793 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
796 for (; entries
-- > 0; fsp
++)
798 me
= g_malloc (sizeof (*me
));
799 me
->me_devname
= g_strdup (fsp
->f_mntfromname
);
800 me
->me_mountdir
= g_strdup (fsp
->f_mntonname
);
801 me
->me_mntroot
= NULL
;
802 me
->me_type
= g_strdup (fsp
->f_fstypename
);
803 me
->me_type_malloced
= 1;
804 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
805 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
806 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
808 mount_list
= g_slist_prepend (mount_list
, me
);
811 #endif /* MOUNTED_GETMNTINFO2 */
813 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
822 val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) NULL
);
828 me
= g_malloc (sizeof (*me
));
829 me
->me_devname
= g_strdup (fsd
.fd_req
.devname
);
830 me
->me_mountdir
= g_strdup (fsd
.fd_req
.path
);
831 me
->me_mntroot
= NULL
;
832 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
833 me
->me_type_malloced
= 0;
834 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
835 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
836 me
->me_dev
= fsd
.fd_req
.dev
;
838 mount_list
= g_slist_prepend (mount_list
, me
);
841 #endif /* MOUNTED_GETMNT. */
843 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
845 /* The next_dev() and fs_stat_dev() system calls give the list of
846 all file systems, including the information returned by statvfs()
847 (fs type, total blocks, free blocks etc.), but without the mount
848 point. But on BeOS all file systems except / are mounted in the
849 rootfs, directly under /.
850 The directory name of the mount point is often, but not always,
851 identical to the volume name of the device.
852 We therefore get the list of subdirectories of /, and the list
853 of all file systems, and match the two lists. */
861 struct rootdir_entry
*next
;
863 struct rootdir_entry
*rootdir_list
;
864 struct rootdir_entry
**rootdir_tail
;
869 /* All volumes are mounted in the rootfs, directly under /. */
871 rootdir_tail
= &rootdir_list
;
872 dirp
= opendir (PATH_SEP_STR
);
877 while ((d
= readdir (dirp
)) != NULL
)
882 if (DIR_IS_DOT (d
->d_name
))
885 if (DIR_IS_DOTDOT (d
->d_name
))
886 name
= g_strdup (PATH_SEP_STR
);
888 name
= g_strconcat (PATH_SEP_STR
, d
->d_name
, (char *) NULL
);
890 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
892 struct rootdir_entry
*re
= g_malloc (sizeof (*re
));
894 re
->dev
= statbuf
.st_dev
;
895 re
->ino
= statbuf
.st_ino
;
897 /* Add to the linked list. */
899 rootdir_tail
= &re
->next
;
906 *rootdir_tail
= NULL
;
908 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
909 if (fs_stat_dev (dev
, &fi
) >= 0)
911 /* Note: fi.dev == dev. */
912 struct rootdir_entry
*re
;
914 for (re
= rootdir_list
; re
; re
= re
->next
)
915 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
918 me
= g_malloc (sizeof (*me
));
920 g_strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
921 me
->me_mountdir
= g_strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
922 me
->me_mntroot
= NULL
;
923 me
->me_type
= g_strdup (fi
.fsh_name
);
924 me
->me_type_malloced
= 1;
927 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
929 mount_list
= g_slist_prepend (mount_list
, me
);
932 while (rootdir_list
!= NULL
)
934 struct rootdir_entry
*re
= rootdir_list
;
936 rootdir_list
= re
->next
;
941 #endif /* MOUNTED_FS_STAT_DEV */
943 #ifdef MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
947 struct statfs
*stats
;
949 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
952 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
954 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
958 bufsize
= (1 + numsys
) * sizeof (*stats
);
959 stats
= g_malloc (bufsize
);
960 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
968 for (counter
= 0; counter
< numsys
; counter
++)
970 me
= g_malloc (sizeof (*me
));
971 me
->me_devname
= g_strdup (stats
[counter
].f_mntfromname
);
972 me
->me_mountdir
= g_strdup (stats
[counter
].f_mntonname
);
973 me
->me_mntroot
= NULL
;
974 me
->me_type
= g_strdup (FS_TYPE (stats
[counter
]));
975 me
->me_type_malloced
= 1;
976 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
977 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
978 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
980 mount_list
= g_slist_prepend (mount_list
, me
);
985 #endif /* MOUNTED_GETFSSTAT */
987 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
990 char *table
= "/etc/mnttab";
993 fp
= fopen (table
, "r");
997 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
999 me
= g_malloc (sizeof (*me
));
1000 me
->me_devname
= g_strdup (mnt
.mt_dev
);
1001 me
->me_mountdir
= g_strdup (mnt
.mt_filsys
);
1002 me
->me_mntroot
= NULL
;
1003 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1005 me
->me_type_malloced
= 0;
1008 char typebuf
[FSTYPSZ
];
1010 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
1011 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
1013 me
->me_type
= g_strdup (typebuf
);
1014 me
->me_type_malloced
= 1;
1017 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1018 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1020 mount_list
= g_slist_prepend (mount_list
, me
);
1025 /* The last fread() call must have failed. */
1026 int saved_errno
= errno
;
1029 errno
= saved_errno
;
1030 goto free_then_fail
;
1033 if (fclose (fp
) == EOF
)
1034 goto free_then_fail
;
1036 #endif /* MOUNTED_FREAD_FSTYP */
1038 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
1040 struct extmnttab mnt
;
1041 const char *table
= MNTTAB
;
1045 /* No locking is needed, because the contents of /etc/mnttab is generated by the kernel. */
1048 fp
= fopen (table
, "r");
1053 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
1055 me
= g_malloc (sizeof *me
);
1056 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1057 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1058 me
->me_mntroot
= NULL
;
1059 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1060 me
->me_type_malloced
= 1;
1061 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1062 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1063 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
1065 mount_list
= g_slist_prepend (mount_list
, me
);
1068 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1069 /* Here ret = -1 means success, ret >= 0 means failure. */
1075 goto free_then_fail
;
1078 #endif /* MOUNTED_GETEXTMNTENT */
1080 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
1083 const char *table
= MNTTAB
;
1088 #if defined F_RDLCK && defined F_SETLKW
1089 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
1090 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
1091 for this file name, we should use their macro name instead.
1092 (Why not just lock MNTTAB directly? We don't know.) */
1094 #define MNTTAB_LOCK "/etc/.mnttab.lock"
1096 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
1101 flock
.l_type
= F_RDLCK
;
1102 flock
.l_whence
= SEEK_SET
;
1105 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
1108 int saved_errno
= errno
;
1110 errno
= saved_errno
;
1114 else if (errno
!= ENOENT
)
1119 fp
= fopen (table
, "r");
1124 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1126 me
= g_malloc (sizeof (*me
));
1127 me
->me_devname
= g_strdup (mnt
.mnt_special
);
1128 me
->me_mountdir
= g_strdup (mnt
.mnt_mountp
);
1129 me
->me_mntroot
= NULL
;
1130 me
->me_type
= g_strdup (mnt
.mnt_fstype
);
1131 me
->me_type_malloced
= 1;
1132 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1133 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1134 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1136 mount_list
= g_slist_prepend (mount_list
, me
);
1139 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1140 /* Here ret = -1 means success, ret >= 0 means failure. */
1143 if (lockfd
>= 0 && close (lockfd
) != 0)
1149 goto free_then_fail
;
1152 #endif /* MOUNTED_GETMNTENT2. */
1154 #ifdef MOUNTED_VMOUNT /* AIX */
1163 /* Ask how many bytes to allocate for the mounted file system info. */
1165 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), entries
) != 0)
1167 entries
= g_malloc (bufsize
);
1169 /* Get the list of mounted file systems. */
1170 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1173 int saved_errno
= errno
;
1176 errno
= saved_errno
;
1180 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1182 char *options
, *ignore
;
1184 vmp
= (struct vmount
*) thisent
;
1185 me
= g_malloc (sizeof (*me
));
1186 if (vmp
->vmt_flags
& MNT_REMOTE
)
1191 /* Prepend the remote dirname. */
1192 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1193 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1194 me
->me_devname
= g_strconcat (host
, ":", dir
, (char *) NULL
);
1199 me
->me_devname
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1201 me
->me_mountdir
= g_strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1202 me
->me_mntroot
= NULL
;
1203 me
->me_type
= g_strdup (fstype_to_string (vmp
->vmt_gfstype
));
1204 me
->me_type_malloced
= 1;
1205 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1206 ignore
= strstr (options
, "ignore");
1207 me
->me_dummy
= (ignore
1208 && (ignore
== options
|| ignore
[-1] == ',')
1209 && (ignore
[sizeof ("ignore") - 1] == ','
1210 || ignore
[sizeof ("ignore") - 1] == '\0'));
1211 me
->me_dev
= (dev_t
) (-1); /* vmt_fsid might be the info we want. */
1213 mount_list
= g_slist_prepend (mount_list
, me
);
1217 #endif /* MOUNTED_VMOUNT. */
1219 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1221 DIR *dirp
= opendir ("/dev/fs");
1222 char node
[9 + NAME_MAX
];
1225 goto free_then_fail
;
1230 struct dirent entry
;
1231 struct dirent
*result
;
1233 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1236 strcpy (node
, "/dev/fs/");
1237 strcat (node
, entry
.d_name
);
1239 if (statvfs (node
, &dev
) == 0)
1241 me
= g_malloc (sizeof *me
);
1242 me
->me_devname
= g_strdup (dev
.f_mntfromname
);
1243 me
->me_mountdir
= g_strdup (dev
.f_mntonname
);
1244 me
->me_mntroot
= NULL
;
1245 me
->me_type
= g_strdup (dev
.f_fstypename
);
1246 me
->me_type_malloced
= 1;
1247 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1248 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1249 me
->me_dev
= (dev_t
) (-1); /* Magic; means not known yet. */
1251 mount_list
= g_slist_prepend (mount_list
, me
);
1256 #endif /* MOUNTED_INTERIX_STATVFS */
1258 return g_slist_reverse (mount_list
);
1262 int saved_errno
= errno
;
1264 g_slist_free_full (mount_list
, (GDestroyNotify
) free_mount_entry
);
1266 errno
= saved_errno
;
1270 #endif /* HAVE_INFOMOUNT_LIST */
1272 /* --------------------------------------------------------------------------------------------- */
1274 #ifdef HAVE_INFOMOUNT_QNX
1276 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1277 ** this via the following code.
1278 ** Note that, as this is based on CWD, it only fills one mount_entry
1279 ** structure. See my_statfs() below for the "other side" of this hack.
1283 read_file_system_list (void)
1285 struct _disk_entry de
;
1288 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1289 struct mount_entry
*me
= NULL
;
1290 static GSList
*list
= NULL
;
1294 me
= (struct mount_entry
*) list
->data
;
1296 g_free (me
->me_devname
);
1297 g_free (me
->me_mountdir
);
1298 g_free (me
->me_mntroot
);
1299 g_free (me
->me_type
);
1303 me
= (struct mount_entry
*) g_malloc (sizeof (struct mount_entry
));
1304 list
= g_slist_prepend (list
, me
);
1307 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1310 fd
= open (dir
, O_RDONLY
);
1314 i
= disk_get_entry (fd
, &de
);
1321 switch (de
.disk_type
)
1348 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1351 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1354 me
->me_devname
= g_strdup (dev
);
1355 me
->me_mountdir
= g_strdup (dir
);
1356 me
->me_mntroot
= NULL
;
1357 me
->me_type
= g_strdup (tp
);
1358 me
->me_dev
= de
.disk_type
;
1362 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1363 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1364 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1365 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1370 #endif /* HAVE_INFOMOUNT_QNX */
1372 /* --------------------------------------------------------------------------------------------- */
1374 #ifdef HAVE_INFOMOUNT
1375 /* Fill in the fields of FSP with information about space usage for
1376 the file system on which FILE resides.
1377 DISK is the device on which FILE is mounted, for space-getting
1378 methods that need to know it.
1379 Return 0 if successful, -1 if not. When returning -1, ensure that
1380 ERRNO is either a system error value, or zero if DISK is NULL
1381 on a system that requires a non-NULL value. */
1383 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1385 #ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
1387 if (statvfs_works ())
1389 struct statvfs vfsd
;
1391 if (statvfs (file
, &vfsd
) < 0)
1394 /* f_frsize isn't guaranteed to be supported. */
1395 fsp
->fsu_blocksize
= (vfsd
.f_frsize
1396 ? PROPAGATE_ALL_ONES (vfsd
.f_frsize
)
1397 : PROPAGATE_ALL_ONES (vfsd
.f_bsize
));
1399 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (vfsd
.f_blocks
);
1400 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (vfsd
.f_bfree
);
1401 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (vfsd
.f_bavail
);
1402 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (vfsd
.f_bavail
) != 0;
1403 fsp
->fsu_files
= PROPAGATE_ALL_ONES (vfsd
.f_files
);
1404 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (vfsd
.f_ffree
);
1410 #if defined STAT_STATVFS64 /* AIX */
1412 struct statvfs64 fsd
;
1414 if (statvfs64 (file
, &fsd
) < 0)
1417 /* f_frsize isn't guaranteed to be supported. */
1419 fsp
->fsu_blocksize
= fsd
.f_frsize
1420 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1421 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1424 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1428 if (statfs (file
, &fsd
) != 1)
1431 fsp
->fsu_blocksize
= 1024;
1432 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1433 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1434 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1435 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1436 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1437 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1439 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1443 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1446 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1448 #elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
1452 if (statfs (file
, &fsd
) < 0)
1455 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_frsize
);
1457 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
1458 Mac OS X < 10.4, FreeBSD < 5.0, \
1459 NetBSD < 3.0, OpenBSD < 4.4 */
1463 if (statfs (file
, &fsd
) < 0)
1466 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1468 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1470 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1471 struct statfs are truncated to 2GB. These conditions detect that
1472 truncation, presumably without botching the 4.1.1 case, in which
1473 the values are not truncated. The correct counts are stored in
1474 undocumented spare fields. */
1475 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1477 fsd
.f_blocks
= fsd
.f_spare
[0];
1478 fsd
.f_bfree
= fsd
.f_spare
[1];
1479 fsd
.f_bavail
= fsd
.f_spare
[2];
1481 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1483 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1487 if (statfs (file
, &fsd
) < 0)
1490 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1492 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix */
1494 #if !defined _SEQUENT_
1495 #define f_bavail f_bfree
1500 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1503 /* Empirically, the block counts on most SVR3 and SVR3-derived
1504 systems seem to always be in terms of 512-byte blocks,
1505 no matter what value f_bsize has. */
1507 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1509 fsp
->fsu_blocksize
= 512;
1514 #if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
1515 || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
1516 || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
1518 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1519 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1520 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1521 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1522 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1523 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1528 (void) disk
; /* avoid argument-unused warning */
1532 #endif /* HAVE_INFOMOUNT */
1534 /* --------------------------------------------------------------------------------------------- */
1535 /*** public functions ****************************************************************************/
1536 /* --------------------------------------------------------------------------------------------- */
1539 free_my_statfs (void)
1541 #ifdef HAVE_INFOMOUNT_LIST
1542 g_slist_free_full (mc_mount_list
, (GDestroyNotify
) free_mount_entry
);
1543 mc_mount_list
= NULL
;
1544 #endif /* HAVE_INFOMOUNT_LIST */
1547 /* --------------------------------------------------------------------------------------------- */
1550 init_my_statfs (void)
1552 #ifdef HAVE_INFOMOUNT_LIST
1554 mc_mount_list
= read_file_system_list ();
1555 #endif /* HAVE_INFOMOUNT_LIST */
1558 /* --------------------------------------------------------------------------------------------- */
1561 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1563 #ifdef HAVE_INFOMOUNT_LIST
1565 struct mount_entry
*entry
= NULL
;
1567 struct fs_usage fs_use
;
1569 for (temp
= mc_mount_list
; temp
!= NULL
; temp
= g_slist_next (temp
))
1571 struct mount_entry
*me
;
1574 me
= (struct mount_entry
*) temp
->data
;
1575 i
= strlen (me
->me_mountdir
);
1576 if (i
> len
&& (strncmp (path
, me
->me_mountdir
, i
) == 0) &&
1577 (entry
== NULL
|| IS_PATH_SEP (path
[i
]) || path
[i
] == '\0'))
1586 memset (&fs_use
, 0, sizeof (fs_use
));
1587 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1589 myfs_stats
->type
= entry
->me_dev
;
1590 myfs_stats
->typename
= entry
->me_type
;
1591 myfs_stats
->mpoint
= entry
->me_mountdir
;
1592 myfs_stats
->mroot
= entry
->me_mntroot
;
1593 myfs_stats
->device
= entry
->me_devname
;
1595 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1596 fs_use
.fsu_blocksize
) >> 10;
1597 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1598 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1599 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1602 #endif /* HAVE_INFOMOUNT_LIST */
1604 #ifdef HAVE_INFOMOUNT_QNX
1606 ** This is the "other side" of the hack to read_file_system_list() above.
1607 ** It's not the most efficient approach, but consumes less memory. It
1608 ** also accommodates QNX's ability to mount filesystems on the fly.
1610 struct mount_entry
*entry
;
1611 struct fs_usage fs_use
;
1613 entry
= read_file_system_list ();
1616 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1618 myfs_stats
->type
= entry
->me_dev
;
1619 myfs_stats
->typename
= entry
->me_type
;
1620 myfs_stats
->mpoint
= entry
->me_mountdir
;
1621 myfs_stats
->mroot
= entry
->me_mntroot
;
1622 myfs_stats
->device
= entry
->me_devname
;
1624 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1625 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1626 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1627 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1630 #endif /* HAVE_INFOMOUNT_QNX */
1632 myfs_stats
->type
= 0;
1633 myfs_stats
->mpoint
= "unknown";
1634 myfs_stats
->device
= "unknown";
1635 myfs_stats
->avail
= 0;
1636 myfs_stats
->total
= 0;
1637 myfs_stats
->nfree
= 0;
1638 myfs_stats
->nodes
= 0;
1642 /* --------------------------------------------------------------------------------------------- */