2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * \brief Source: list of mounted filesystems
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
41 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
42 #include <sys/statvfs.h>
44 /* Don't include backward-compatibility files unless they're needed.
45 Eventually we'd like to remove all this cruft. */
50 /* This header needs to be included before sys/mount.h on *BSD */
51 #ifdef HAVE_SYS_PARAM_H
52 #include <sys/param.h>
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
124 #ifdef MOUNTED_FREAD /* SVR2. */
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
134 #ifdef MOUNTED_LISTMNTENT
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
142 #ifdef MOUNTED_VMOUNT /* AIX. */
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
167 #define MNT_IGNORE(M) 0
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
205 # define ME_DUMMY(Fs_name, Fs_type) \
206 (strcmp (Fs_type, "autofs") == 0 \
207 || strcmp (Fs_type, "none") == 0 \
208 || strcmp (Fs_type, "proc") == 0 \
209 || strcmp (Fs_type, "subfs") == 0 \
210 /* for NetBSD 3.0 */ \
211 || strcmp (Fs_type, "kernfs") == 0 \
213 || strcmp (Fs_type, "ignore") == 0)
218 #define ME_REMOTE me_remote
219 /* All cygwin mount points include `:' or start with `//'; so it
220 requires a native Windows call to determine remote disks. */
222 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
224 if (fs_name
[0] && fs_name
[1] == ':')
227 sprintf (drive
, "%c:\\", fs_name
[0]);
228 switch (GetDriveType (drive
))
230 case DRIVE_REMOVABLE
:
241 /* A file system is `remote' if its Fs_name contains a `:'
242 or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
243 # define ME_REMOTE(Fs_name, Fs_type) \
244 (strchr (Fs_name, ':') != NULL \
245 || ((Fs_name)[0] == '/' \
246 && (Fs_name)[1] == '/' \
247 && (strcmp (Fs_type, "smbfs") == 0 || strcmp (Fs_type, "cifs") == 0)))
250 /* Many space usage primitives use all 1 bits to denote a value that is
251 not applicable or unknown. Propagate this information by returning
252 a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
253 is unsigned and narrower than uintmax_t. */
254 #define PROPAGATE_ALL_ONES(x) \
255 ((sizeof (x) < sizeof (uintmax_t) \
256 && (~ (x) == (sizeof (x) < sizeof (int) \
257 ? - (1 << (sizeof (x) * CHAR_BIT)) \
259 ? UINTMAX_MAX : (uintmax_t) (x))
261 /* Extract the top bit of X as an uintmax_t value. */
262 #define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
264 /* If a value is negative, many space usage primitives store it into an
265 integer variable by assignment, even if the variable's type is unsigned.
266 So, if a space usage variable X's top bit is set, convert X to the
267 uintmax_t value V such that (- (uintmax_t) V) is the negative of
268 the original value. If X's top bit is clear, just yield X.
269 Use PROPAGATE_TOP_BIT if the original value might be negative;
270 otherwise, use PROPAGATE_ALL_ONES. */
271 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
273 #ifdef STAT_READ_FILSYS /* SVR2 */
274 /* Set errno to zero upon EOF. */
275 #define ZERO_BYTE_TRANSFER_ERRNO 0
278 #define IS_EINTR(x) ((x) == EINTR)
280 #define IS_EINTR(x) 0
282 #endif /* STAT_READ_FILSYS */
284 /*** file scope type declarations ****************************************************************/
286 /* A mount table entry. */
289 char *me_devname
; /* Device node name, including "/dev/". */
290 char *me_mountdir
; /* Mount point directory name. */
291 char *me_type
; /* "nfs", "4.2", etc. */
292 dev_t me_dev
; /* Device number of me_mountdir. */
293 unsigned int me_dummy
: 1; /* Nonzero for dummy file systems. */
294 unsigned int me_remote
: 1; /* Nonzero for remote fileystems. */
295 unsigned int me_type_malloced
: 1; /* Nonzero if me_type was malloced. */
296 struct mount_entry
*me_next
;
301 uintmax_t fsu_blocksize
; /* Size of a block. */
302 uintmax_t fsu_blocks
; /* Total blocks. */
303 uintmax_t fsu_bfree
; /* Free blocks available to superuser. */
304 uintmax_t fsu_bavail
; /* Free blocks available to non-superuser. */
305 int fsu_bavail_top_bit_set
; /* 1 if fsu_bavail represents a value < 0. */
306 uintmax_t fsu_files
; /* Total file nodes. */
307 uintmax_t fsu_ffree
; /* Free file nodes. */
310 /*** file scope variables ************************************************************************/
312 #ifdef HAVE_INFOMOUNT_LIST
313 static struct mount_entry
*mc_mount_list
= NULL
;
314 #endif /* HAVE_INFOMOUNT_LIST */
316 /*** file scope functions ************************************************************************/
317 /* --------------------------------------------------------------------------------------------- */
319 #ifdef HAVE_INFOMOUNT_LIST
321 free_mount_entry (struct mount_entry
*me
)
326 free (me
->me_devname
);
328 free (me
->me_mountdir
);
329 if (me
->me_type
&& me
->me_type_malloced
)
334 /* --------------------------------------------------------------------------------------------- */
336 #ifdef MOUNTED_GETMNTINFO
338 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
340 fstype_to_string (short int t
)
432 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
434 /* --------------------------------------------------------------------------------------------- */
437 fsp_to_string (const struct statfs
*fsp
)
439 #if HAVE_STRUCT_STATFS_F_FSTYPENAME
440 return (char *) (fsp
->f_fstypename
);
442 return fstype_to_string (fsp
->f_type
);
445 #endif /* MOUNTED_GETMNTINFO */
447 /* --------------------------------------------------------------------------------------------- */
449 #ifdef MOUNTED_VMOUNT /* AIX. */
451 fstype_to_string (int t
)
455 e
= getvfsbytype (t
);
456 if (!e
|| !e
->vfsent_name
)
459 return e
->vfsent_name
;
461 #endif /* MOUNTED_VMOUNT */
463 /* --------------------------------------------------------------------------------------------- */
465 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
467 /* Return the device number from MOUNT_OPTIONS, if possible.
468 Otherwise return (dev_t) -1. */
470 /* --------------------------------------------------------------------------------------------- */
473 dev_from_mount_options (char const *mount_options
)
475 /* GNU/Linux allows file system implementations to define their own
476 meaning for "dev=" mount options, so don't trust the meaning
479 static char const dev_pattern
[] = ",dev=";
480 char const *devopt
= strstr (mount_options
, dev_pattern
);
484 char const *optval
= devopt
+ sizeof (dev_pattern
) - 1;
486 unsigned long int dev
;
488 dev
= strtoul (optval
, &optvalend
, 16);
489 if (optval
!= optvalend
490 && (*optvalend
== '\0' || *optvalend
== ',')
491 && !(dev
== ULONG_MAX
&& errno
== ERANGE
) && dev
== (dev_t
) dev
)
496 (void) mount_options
;
502 /* --------------------------------------------------------------------------------------------- */
504 #if defined _AIX && defined _I386
505 /* AIX PS/2 does not supply statfs. */
508 statfs (char *file
, struct statfs
*fsb
)
513 if (stat (file
, &stats
) != 0)
515 if (dustat (stats
.st_dev
, 0, &fsd
, sizeof (fsd
)))
518 fsb
->f_bsize
= fsd
.du_bsize
;
519 fsb
->f_blocks
= fsd
.du_fsize
- fsd
.du_isize
;
520 fsb
->f_bfree
= fsd
.du_tfree
;
521 fsb
->f_bavail
= fsd
.du_tfree
;
522 fsb
->f_files
= (fsd
.du_isize
- 2) * fsd
.du_inopb
;
523 fsb
->f_ffree
= fsd
.du_tinode
;
524 fsb
->f_fsid
.val
[0] = fsd
.du_site
;
525 fsb
->f_fsid
.val
[1] = fsd
.du_pckno
;
529 #endif /* _AIX && _I386 */
531 /* --------------------------------------------------------------------------------------------- */
533 /* Return a list of the currently mounted file systems, or NULL on error.
534 Add each entry to the tail of the list so that they stay in order.
535 If NEED_FS_TYPE is true, ensure that the file system type fields in
536 the returned list are valid. Otherwise, they might not be. */
538 static struct mount_entry
*
539 read_file_system_list (int need_fs_type
)
541 struct mount_entry
*mount_list
;
542 struct mount_entry
*me
;
543 struct mount_entry
**mtail
= &mount_list
;
545 #ifdef MOUNTED_LISTMNTENT
547 struct tabmntent
*mntlist
, *p
;
549 struct mount_entry
*me
;
551 /* the third and fourth arguments could be used to filter mounts,
552 but Crays doesn't seem to have any mounts that we want to
553 remove. Specifically, automount create normal NFS mounts.
556 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
558 for (p
= mntlist
; p
; p
= p
->next
)
561 me
= malloc (sizeof (*me
));
562 me
->me_devname
= strdup (mnt
->mnt_fsname
);
563 me
->me_mountdir
= strdup (mnt
->mnt_dir
);
564 me
->me_type
= strdup (mnt
->mnt_type
);
565 me
->me_type_malloced
= 1;
566 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
567 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
570 mtail
= &me
->me_next
;
572 freemntlist (mntlist
);
576 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
579 const char *table
= MOUNTED
;
582 fp
= setmntent (table
, "r");
586 while ((mnt
= getmntent (fp
)))
588 me
= malloc (sizeof (*me
));
589 me
->me_devname
= strdup (mnt
->mnt_fsname
);
590 me
->me_mountdir
= strdup (mnt
->mnt_dir
);
591 me
->me_type
= strdup (mnt
->mnt_type
);
592 me
->me_type_malloced
= 1;
593 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
594 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
595 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
597 /* Add to the linked list. */
599 mtail
= &me
->me_next
;
602 if (endmntent (fp
) == 0)
605 #endif /* MOUNTED_GETMNTENT1. */
607 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
612 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
615 for (; entries
-- > 0; fsp
++)
617 char *fs_type
= fsp_to_string (fsp
);
619 me
= malloc (sizeof (*me
));
620 me
->me_devname
= strdup (fsp
->f_mntfromname
);
621 me
->me_mountdir
= strdup (fsp
->f_mntonname
);
622 me
->me_type
= fs_type
;
623 me
->me_type_malloced
= 0;
624 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
625 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
626 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
628 /* Add to the linked list. */
630 mtail
= &me
->me_next
;
633 #endif /* MOUNTED_GETMNTINFO */
635 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
640 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
643 for (; entries
-- > 0; fsp
++)
645 me
= malloc (sizeof (*me
));
646 me
->me_devname
= strdup (fsp
->f_mntfromname
);
647 me
->me_mountdir
= strdup (fsp
->f_mntonname
);
648 me
->me_type
= strdup (fsp
->f_fstypename
);
649 me
->me_type_malloced
= 1;
650 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
651 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
652 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
654 /* Add to the linked list. */
656 mtail
= &me
->me_next
;
659 #endif /* MOUNTED_GETMNTINFO2 */
661 #ifdef MOUNTED_GETMNT /* Ultrix. */
667 while (errno
= 0, 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, (char *) 0)))
669 me
= malloc (sizeof (*me
));
670 me
->me_devname
= strdup (fsd
.fd_req
.devname
);
671 me
->me_mountdir
= strdup (fsd
.fd_req
.path
);
672 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
673 me
->me_type_malloced
= 0;
674 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
675 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
676 me
->me_dev
= fsd
.fd_req
.dev
;
678 /* Add to the linked list. */
680 mtail
= &me
->me_next
;
685 #endif /* MOUNTED_GETMNT. */
687 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
689 /* The next_dev() and fs_stat_dev() system calls give the list of
690 all file systems, including the information returned by statvfs()
691 (fs type, total blocks, free blocks etc.), but without the mount
692 point. But on BeOS all file systems except / are mounted in the
693 rootfs, directly under /.
694 The directory name of the mount point is often, but not always,
695 identical to the volume name of the device.
696 We therefore get the list of subdirectories of /, and the list
697 of all file systems, and match the two lists. */
705 struct rootdir_entry
*next
;
707 struct rootdir_entry
*rootdir_list
;
708 struct rootdir_entry
**rootdir_tail
;
713 /* All volumes are mounted in the rootfs, directly under /. */
715 rootdir_tail
= &rootdir_list
;
716 dirp
= opendir ("/");
721 while ((d
= readdir (dirp
)) != NULL
)
726 if (strcmp (d
->d_name
, "..") == 0)
729 if (strcmp (d
->d_name
, ".") == 0)
733 name
= malloc (1 + strlen (d
->d_name
) + 1);
735 strcpy (name
+ 1, d
->d_name
);
738 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
740 struct rootdir_entry
*re
= malloc (sizeof (*re
));
742 re
->dev
= statbuf
.st_dev
;
743 re
->ino
= statbuf
.st_ino
;
745 /* Add to the linked list. */
747 rootdir_tail
= &re
->next
;
754 *rootdir_tail
= NULL
;
756 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0;)
757 if (fs_stat_dev (dev
, &fi
) >= 0)
759 /* Note: fi.dev == dev. */
760 struct rootdir_entry
*re
;
762 for (re
= rootdir_list
; re
; re
= re
->next
)
763 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
766 me
= malloc (sizeof (*me
));
767 me
->me_devname
= strdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
768 me
->me_mountdir
= strdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
769 me
->me_type
= strdup (fi
.fsh_name
);
770 me
->me_type_malloced
= 1;
773 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
775 /* Add to the linked list. */
777 mtail
= &me
->me_next
;
781 while (rootdir_list
!= NULL
)
783 struct rootdir_entry
*re
= rootdir_list
;
784 rootdir_list
= re
->next
;
789 #endif /* MOUNTED_FS_STAT_DEV */
791 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
795 struct statfs
*stats
;
797 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
800 if (SIZE_MAX
/ sizeof (*stats
) <= numsys
)
802 fprintf (stderr
, "%s\n", _("Memory exhausted!"));
806 bufsize
= (1 + numsys
) * sizeof (*stats
);
807 stats
= malloc (bufsize
);
808 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
816 for (counter
= 0; counter
< numsys
; counter
++)
818 me
= malloc (sizeof (*me
));
819 me
->me_devname
= strdup (stats
[counter
].f_mntfromname
);
820 me
->me_mountdir
= strdup (stats
[counter
].f_mntonname
);
821 me
->me_type
= strdup (FS_TYPE (stats
[counter
]));
822 me
->me_type_malloced
= 1;
823 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
824 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
825 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
827 /* Add to the linked list. */
829 mtail
= &me
->me_next
;
834 #endif /* MOUNTED_GETFSSTAT */
836 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
839 char *table
= "/etc/mnttab";
842 fp
= fopen (table
, "r");
846 while (fread (&mnt
, sizeof (mnt
), 1, fp
) > 0)
848 me
= malloc (sizeof (*me
));
849 #ifdef GETFSTYP /* SVR3. */
850 me
->me_devname
= strdup (mnt
.mt_dev
);
852 me
->me_devname
= malloc (strlen (mnt
.mt_dev
) + 6);
853 strcpy (me
->me_devname
, "/dev/");
854 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
856 me
->me_mountdir
= strdup (mnt
.mt_filsys
);
857 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
859 me
->me_type_malloced
= 0;
860 #ifdef GETFSTYP /* SVR3. */
864 char typebuf
[FSTYPSZ
];
866 if (statfs (me
->me_mountdir
, &fsd
, sizeof (fsd
), 0) != -1
867 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
869 me
->me_type
= strdup (typebuf
);
870 me
->me_type_malloced
= 1;
874 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
875 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
877 /* Add to the linked list. */
879 mtail
= &me
->me_next
;
884 /* The last fread() call must have failed. */
885 int saved_errno
= errno
;
891 if (fclose (fp
) == EOF
)
894 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
896 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
898 struct mntent
**mnttbl
= getmnttbl (), **ent
;
899 for (ent
= mnttbl
; *ent
; ent
++)
901 me
= malloc (sizeof (*me
));
902 me
->me_devname
= strdup ((*ent
)->mt_resource
);
903 me
->me_mountdir
= strdup ((*ent
)->mt_directory
);
904 me
->me_type
= strdup ((*ent
)->mt_fstype
);
905 me
->me_type_malloced
= 1;
906 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
907 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
908 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
910 /* Add to the linked list. */
912 mtail
= &me
->me_next
;
918 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
921 char *table
= MNTTAB
;
926 #if defined F_RDLCK && defined F_SETLKW
927 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
928 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
929 for this file name, we should use their macro name instead.
930 (Why not just lock MNTTAB directly? We don't know.) */
932 #define MNTTAB_LOCK "/etc/.mnttab.lock"
934 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
938 flock
.l_type
= F_RDLCK
;
939 flock
.l_whence
= SEEK_SET
;
942 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
945 int saved_errno
= errno
;
951 else if (errno
!= ENOENT
)
956 fp
= fopen (table
, "r");
961 while ((ret
= getmntent (fp
, &mnt
)) == 0)
963 me
= malloc (sizeof (*me
));
964 me
->me_devname
= strdup (mnt
.mnt_special
);
965 me
->me_mountdir
= strdup (mnt
.mnt_mountp
);
966 me
->me_type
= strdup (mnt
.mnt_fstype
);
967 me
->me_type_malloced
= 1;
968 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
969 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
970 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
972 /* Add to the linked list. */
974 mtail
= &me
->me_next
;
977 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
980 if (0 <= lockfd
&& close (lockfd
) != 0)
989 #endif /* MOUNTED_GETMNTENT2. */
991 #ifdef MOUNTED_VMOUNT /* AIX. */
994 char *entries
, *thisent
;
999 /* Ask how many bytes to allocate for the mounted file system info. */
1000 if (mntctl (MCTL_QUERY
, sizeof (bufsize
), (struct vmount
*) &bufsize
) != 0)
1002 entries
= malloc (bufsize
);
1004 /* Get the list of mounted file systems. */
1005 n_entries
= mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
1008 int saved_errno
= errno
;
1010 errno
= saved_errno
;
1014 for (i
= 0, thisent
= entries
; i
< n_entries
; i
++, thisent
+= vmp
->vmt_length
)
1016 char *options
, *ignore
;
1018 vmp
= (struct vmount
*) thisent
;
1019 me
= malloc (sizeof (*me
));
1020 if (vmp
->vmt_flags
& MNT_REMOTE
)
1025 /* Prepend the remote dirname. */
1026 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1027 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1028 me
->me_devname
= malloc (strlen (host
) + strlen (dir
) + 2);
1029 strcpy (me
->me_devname
, host
);
1030 strcat (me
->me_devname
, ":");
1031 strcat (me
->me_devname
, dir
);
1036 me
->me_devname
= strdup (thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1038 me
->me_mountdir
= strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1039 me
->me_type
= strdup (fstype_to_string (vmp
->vmt_gfstype
));
1040 me
->me_type_malloced
= 1;
1041 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1042 ignore
= strstr (options
, "ignore");
1043 me
->me_dummy
= (ignore
1044 && (ignore
== options
|| ignore
[-1] == ',')
1045 && (ignore
[sizeof ("ignore") - 1] == ','
1046 || ignore
[sizeof ("ignore") - 1] == '\0'));
1047 me
->me_dev
= (dev_t
)(-1); /* vmt_fsid might be the info we want. */
1049 /* Add to the linked list. */
1051 mtail
= &me
->me_next
;
1055 #endif /* MOUNTED_VMOUNT. */
1058 #ifdef MOUNTED_INTERIX_STATVFS
1060 DIR *dirp
= opendir ("/dev/fs");
1061 char node
[9 + NAME_MAX
];
1064 goto free_then_fail
;
1069 struct dirent entry
;
1070 struct dirent
*result
;
1072 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1075 strcpy (node
, "/dev/fs/");
1076 strcat (node
, entry
.d_name
);
1078 if (statvfs (node
, &dev
) == 0)
1080 me
= malloc (sizeof *me
);
1081 me
->me_devname
= strdup (dev
.f_mntfromname
);
1082 me
->me_mountdir
= strdup (dev
.f_mntonname
);
1083 me
->me_type
= strdup (dev
.f_fstypename
);
1084 me
->me_type_malloced
= 1;
1085 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1086 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1087 me
->me_dev
= (dev_t
) - 1; /* Magic; means not known yet. */
1089 /* Add to the linked list. */
1091 mtail
= &me
->me_next
;
1095 #endif /* MOUNTED_INTERIX_STATVFS */
1097 (void) need_fs_type
; /* avoid argument-unused warning */
1104 int saved_errno
= errno
;
1109 me
= mount_list
->me_next
;
1110 free (mount_list
->me_devname
);
1111 free (mount_list
->me_mountdir
);
1112 if (mount_list
->me_type_malloced
)
1113 free (mount_list
->me_type
);
1118 errno
= saved_errno
;
1123 #endif /* HAVE_INFOMOUNT_LIST */
1125 /* --------------------------------------------------------------------------------------------- */
1127 #ifdef HAVE_INFOMOUNT_QNX
1129 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
1130 ** this via the following code.
1131 ** Note that, as this is based on CWD, it only fills one mount_entry
1132 ** structure. See my_statfs() in utilunix.c for the "other side" of
1136 static struct mount_entry
*
1137 read_file_system_list (int need_fs_type
, int all_fs
)
1139 struct _disk_entry de
;
1142 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
1144 static struct mount_entry
*me
= NULL
;
1149 free (me
->me_devname
);
1150 if (me
->me_mountdir
)
1151 free (me
->me_mountdir
);
1156 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
1158 if (!getcwd (dir
, _POSIX_PATH_MAX
))
1161 fd
= open (dir
, O_RDONLY
);
1165 i
= disk_get_entry (fd
, &de
);
1172 switch (de
.disk_type
)
1199 if (fsys_get_mount_dev (dir
, &dev
) == -1)
1202 if (fsys_get_mount_pt (dev
, &dir
) == -1)
1205 me
->me_devname
= strdup (dev
);
1206 me
->me_mountdir
= strdup (dir
);
1207 me
->me_type
= strdup (tp
);
1208 me
->me_dev
= de
.disk_type
;
1212 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
1213 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
1214 fprintf (stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
1215 fprintf (stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
1220 #endif /* HAVE_INFOMOUNT_QNX */
1222 /* --------------------------------------------------------------------------------------------- */
1224 #ifdef STAT_READ_FILSYS /* SVR2 */
1226 /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
1227 interrupted. Return the actual number of bytes read(written), zero for EOF,
1228 or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */
1230 safe_read (int fd
, void *buf
, size_t count
)
1232 /* Work around a bug in Tru64 5.1. Attempting to read more than
1233 INT_MAX bytes fails with errno == EINVAL. See
1234 <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
1235 When decreasing COUNT, keep it block-aligned. */
1236 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1240 ssize_t result
= read (fd
, buf
, count
);
1244 else if (IS_EINTR (errno
))
1246 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1247 count
= BUGGY_READ_MAXIMUM
;
1253 /* --------------------------------------------------------------------------------------------- */
1255 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1256 interrupted or if a partial write(read) occurs. Return the number
1257 of bytes transferred.
1258 When writing, set errno if fewer than COUNT bytes are written.
1259 When reading, if fewer than COUNT bytes are read, you must examine
1260 errno to distinguish failure from EOF (errno == 0). */
1263 full_read (int fd
, void *buf
, size_t count
)
1266 char *ptr
= (char *) buf
;
1270 size_t n_rw
= safe_read (fd
, ptr
, count
);
1271 if (n_rw
== (size_t) (-1))
1275 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1286 #endif /* STAT_READ_FILSYS */
1288 /* --------------------------------------------------------------------------------------------- */
1290 #ifdef HAVE_INFOMOUNT
1291 /* Fill in the fields of FSP with information about space usage for
1292 the file system on which FILE resides.
1293 DISK is the device on which FILE is mounted, for space-getting
1294 methods that need to know it.
1295 Return 0 if successful, -1 if not. When returning -1, ensure that
1296 ERRNO is either a system error value, or zero if DISK is NULL
1297 on a system that requires a non-NULL value. */
1299 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1301 #ifdef STAT_STATVFS /* POSIX, except glibc/Linux */
1305 if (statvfs (file
, &fsd
) < 0)
1308 /* f_frsize isn't guaranteed to be supported. */
1309 fsp
->fsu_blocksize
= (fsd
.f_frsize
1310 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
) : PROPAGATE_ALL_ONES (fsd
.f_bsize
));
1312 #elif defined STAT_STATVFS64 /* AIX */
1314 struct statvfs64 fsd
;
1316 if (statvfs64 (file
, &fsd
) < 0)
1319 /* f_frsize isn't guaranteed to be supported. */
1320 fsp
->fsu_blocksize
= (fsd
.f_frsize
1321 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
) : PROPAGATE_ALL_ONES (fsd
.f_bsize
));
1323 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1327 if (statfs (file
, &fsd
) != 1)
1330 fsp
->fsu_blocksize
= 1024;
1331 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1332 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1333 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1334 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1335 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1336 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1338 #elif defined STAT_READ_FILSYS /* SVR2 */
1340 #define SUPERBOFF (SUPERB * 512)
1352 fd
= open (disk
, O_RDONLY
);
1355 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1356 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1363 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1364 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1365 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1366 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1367 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1368 fsp
->fsu_files
= (fsd
.s_isize
== -1
1369 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1370 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1372 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1376 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1379 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1381 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux, 4.3BSD, SunOS 4, \
1382 MacOS X < 10.4, FreeBSD < 5.0, \
1383 NetBSD < 3.0, OpenBSD < 4.4 */
1387 if (statfs (file
, &fsd
) < 0)
1390 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1392 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1394 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1395 struct statfs are truncated to 2GB. These conditions detect that
1396 truncation, presumably without botching the 4.1.1 case, in which
1397 the values are not truncated. The correct counts are stored in
1398 undocumented spare fields. */
1399 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1401 fsd
.f_blocks
= fsd
.f_spare
[0];
1402 fsd
.f_bfree
= fsd
.f_spare
[1];
1403 fsd
.f_bavail
= fsd
.f_spare
[2];
1405 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1407 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1411 if (statfs (file
, &fsd
) < 0)
1414 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1416 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1419 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1420 #define f_bavail f_bfree
1425 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1428 /* Empirically, the block counts on most SVR3 and SVR3-derived
1429 systems seem to always be in terms of 512-byte blocks,
1430 no matter what value f_bsize has. */
1431 #if defined _AIX || defined _CRAY
1432 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1434 fsp
->fsu_blocksize
= 512;
1439 #if (defined STAT_STATVFS || defined STAT_STATVFS64 \
1440 || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
1442 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1443 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1444 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1445 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1446 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1447 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1451 (void) disk
; /* avoid argument-unused warning */
1454 #endif /* HAVE_INFOMOUNT */
1456 /* --------------------------------------------------------------------------------------------- */
1457 /*** public functions ****************************************************************************/
1458 /* --------------------------------------------------------------------------------------------- */
1461 free_my_statfs (void)
1463 #ifdef HAVE_INFOMOUNT_LIST
1464 while (mc_mount_list
!= NULL
)
1466 struct mount_entry
*next
;
1468 next
= mc_mount_list
->me_next
;
1469 free_mount_entry (mc_mount_list
);
1470 mc_mount_list
= next
;
1473 mc_mount_list
= NULL
;
1474 #endif /* HAVE_INFOMOUNT_LIST */
1477 /* --------------------------------------------------------------------------------------------- */
1480 init_my_statfs (void)
1482 #ifdef HAVE_INFOMOUNT_LIST
1484 mc_mount_list
= read_file_system_list (1);
1485 #endif /* HAVE_INFOMOUNT_LIST */
1488 /* --------------------------------------------------------------------------------------------- */
1491 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1493 #ifdef HAVE_INFOMOUNT_LIST
1495 struct mount_entry
*entry
= NULL
;
1496 struct mount_entry
*temp
= mc_mount_list
;
1497 struct fs_usage fs_use
;
1501 i
= strlen (temp
->me_mountdir
);
1502 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1503 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == '\0'))
1508 temp
= temp
->me_next
;
1513 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1514 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1516 myfs_stats
->type
= entry
->me_dev
;
1517 myfs_stats
->typename
= entry
->me_type
;
1518 myfs_stats
->mpoint
= entry
->me_mountdir
;
1519 myfs_stats
->device
= entry
->me_devname
;
1520 myfs_stats
->avail
= ((uintmax_t) (getuid () ? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) * fs_use
.fsu_blocksize
) >> 10;
1521 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1522 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1523 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1526 #endif /* HAVE_INFOMOUNT_LIST */
1528 #ifdef HAVE_INFOMOUNT_QNX
1530 ** This is the "other side" of the hack to read_file_system_list() in
1532 ** It's not the most efficient approach, but consumes less memory. It
1533 ** also accomodates QNX's ability to mount filesystems on the fly.
1535 struct mount_entry
*entry
;
1536 struct fs_usage fs_use
;
1538 entry
= read_file_system_list (0, 0);
1541 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1543 myfs_stats
->type
= entry
->me_dev
;
1544 myfs_stats
->typename
= entry
->me_type
;
1545 myfs_stats
->mpoint
= entry
->me_mountdir
;
1546 myfs_stats
->device
= entry
->me_devname
;
1548 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1549 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1550 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1551 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1554 #endif /* HAVE_INFOMOUNT_QNX */
1556 myfs_stats
->type
= 0;
1557 myfs_stats
->mpoint
= "unknown";
1558 myfs_stats
->device
= "unknown";
1559 myfs_stats
->avail
= 0;
1560 myfs_stats
->total
= 0;
1561 myfs_stats
->nfree
= 0;
1562 myfs_stats
->nodes
= 0;
1566 /* --------------------------------------------------------------------------------------------- */