2 Return a list of mounted file systems
4 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
7 Copyright (C) 1991, 1992, 2011
8 The Free Software Foundation, Inc.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * \brief Source: list of mounted filesystems
36 #include <stdint.h> /* SIZE_MAX */
37 #include <sys/types.h>
41 /* This header needs to be included before sys/mount.h on *BSD */
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
46 #if defined STAT_STATVFS || defined STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
47 #include <sys/statvfs.h>
49 /* Don't include backward-compatibility files unless they're needed.
50 Eventually we'd like to remove all this cruft. */
55 #ifdef MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 #ifdef HAVE_SYS_UCRED_H
57 #include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
58 NGROUPS is used as an array dimension in ucred.h */
59 #include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
61 #ifdef HAVE_SYS_MOUNT_H
62 #include <sys/mount.h>
64 #ifdef HAVE_SYS_FS_TYPES_H
65 #include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
67 #ifdef HAVE_STRUCT_FSSTAT_F_FSTYPENAME
68 #define FS_TYPE(Ent) ((Ent).f_fstypename)
70 #define FS_TYPE(Ent) mnt_names[(Ent).f_type]
72 #endif /* MOUNTED_GETFSSTAT */
73 #endif /* STAT_STATVFS || STAT_STATVFS64 */
78 #ifdef HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
79 #include <sys/fs/s5param.h>
81 #if defined HAVE_SYS_FILSYS_H && !defined _CRAY
82 #include <sys/filsys.h> /* SVR2 */
84 #ifdef HAVE_SYS_STATFS_H
85 #include <sys/statfs.h>
87 #ifdef HAVE_DUSTAT_H /* AIX PS/2 */
88 #include <sys/dustat.h>
91 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
94 #ifdef _PATH_MOUNTED /* GNU libc */
95 #define MOUNTED _PATH_MOUNTED
97 #ifdef MNT_MNTTAB /* HP-UX. */
98 #define MOUNTED MNT_MNTTAB
100 #ifdef MNTTABNAME /* Dynix. */
101 #define MOUNTED MNTTABNAME
106 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
107 #include <sys/mount.h>
110 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
111 #include <sys/statvfs.h>
114 #ifdef MOUNTED_GETMNT /* Ultrix. */
115 #include <sys/mount.h>
116 #include <sys/fs_types.h>
119 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
124 #ifdef MOUNTED_FREAD /* SVR2. */
128 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
130 #include <sys/fstyp.h>
131 #include <sys/statfs.h>
134 #ifdef MOUNTED_LISTMNTENT
138 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
139 #include <sys/mnttab.h>
142 #ifdef MOUNTED_VMOUNT /* AIX. */
147 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
148 #include <sys/statvfs.h>
153 /* So special that it's not worth putting this in autoconf. */
154 #undef MOUNTED_FREAD_FSTYP
155 #define MOUNTED_GETMNTTBL
158 #ifdef HAVE_SYS_MNTENT_H
159 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
160 #include <sys/mntent.h>
164 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
165 #define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
167 #define MNT_IGNORE(M) 0
170 #ifdef HAVE_INFOMOUNT_QNX
171 #include <sys/disk.h>
172 #include <sys/fsys.h>
175 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
176 #include <sys/statvfs.h>
179 #include "lib/global.h"
180 #include "mountlist.h"
182 /*** global variables ****************************************************************************/
184 /*** file scope macro definitions ****************************************************************/
186 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
187 #define HAVE_INFOMOUNT_QNX
190 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
191 #define HAVE_INFOMOUNT
194 /* The results of open() in this file are not used with fchdir,
195 therefore save some unnecessary work in fchdir.c. */
199 /* The results of opendir() in this file are not used with dirfd and fchdir,
200 therefore save some unnecessary work in fchdir.c. */
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 #ifdef 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. */
1237 enum { BUGGY_READ_MAXIMUM
= INT_MAX
& ~8191 };
1242 ssize_t result
= read (fd
, buf
, count
);
1246 else if (IS_EINTR (errno
))
1248 else if (errno
== EINVAL
&& BUGGY_READ_MAXIMUM
< count
)
1249 count
= BUGGY_READ_MAXIMUM
;
1255 /* --------------------------------------------------------------------------------------------- */
1257 /* Read COUNT bytes at BUF to(from) descriptor FD, retrying if
1258 interrupted or if a partial write(read) occurs. Return the number
1259 of bytes transferred.
1260 When writing, set errno if fewer than COUNT bytes are written.
1261 When reading, if fewer than COUNT bytes are read, you must examine
1262 errno to distinguish failure from EOF (errno == 0). */
1265 full_read (int fd
, void *buf
, size_t count
)
1268 char *ptr
= (char *) buf
;
1272 size_t n_rw
= safe_read (fd
, ptr
, count
);
1273 if (n_rw
== (size_t) (-1))
1277 errno
= ZERO_BYTE_TRANSFER_ERRNO
;
1288 #endif /* STAT_READ_FILSYS */
1290 /* --------------------------------------------------------------------------------------------- */
1292 #ifdef HAVE_INFOMOUNT
1293 /* Fill in the fields of FSP with information about space usage for
1294 the file system on which FILE resides.
1295 DISK is the device on which FILE is mounted, for space-getting
1296 methods that need to know it.
1297 Return 0 if successful, -1 if not. When returning -1, ensure that
1298 ERRNO is either a system error value, or zero if DISK is NULL
1299 on a system that requires a non-NULL value. */
1301 get_fs_usage (char const *file
, char const *disk
, struct fs_usage
*fsp
)
1303 #ifdef STAT_STATVFS /* POSIX, except glibc/Linux */
1307 if (statvfs (file
, &fsd
) < 0)
1310 /* f_frsize isn't guaranteed to be supported. */
1312 fsp
->fsu_blocksize
= fsd
.f_frsize
1313 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1314 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1317 #elif defined STAT_STATVFS64 /* AIX */
1319 struct statvfs64 fsd
;
1321 if (statvfs64 (file
, &fsd
) < 0)
1324 /* f_frsize isn't guaranteed to be supported. */
1326 fsp
->fsu_blocksize
= fsd
.f_frsize
1327 ? PROPAGATE_ALL_ONES (fsd
.f_frsize
)
1328 : PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1331 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
1335 if (statfs (file
, &fsd
) != 1)
1338 fsp
->fsu_blocksize
= 1024;
1339 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.fd_req
.btot
);
1340 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.bfree
);
1341 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.fd_req
.bfreen
);
1342 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.fd_req
.bfreen
) != 0;
1343 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gtot
);
1344 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.fd_req
.gfree
);
1346 #elif defined STAT_READ_FILSYS /* SVR2 */
1348 #define SUPERBOFF (SUPERB * 512)
1360 fd
= open (disk
, O_RDONLY
);
1363 lseek (fd
, (off_t
) SUPERBOFF
, 0);
1364 if (full_read (fd
, (char *) &fsd
, sizeof (fsd
)) != sizeof (fsd
))
1371 fsp
->fsu_blocksize
= (fsd
.s_type
== Fs2b
? 1024 : 512);
1372 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.s_fsize
);
1373 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.s_tfree
);
1374 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.s_tfree
);
1375 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.s_tfree
) != 0;
1376 fsp
->fsu_files
= (fsd
.s_isize
== -1
1377 ? UINTMAX_MAX
: (fsd
.s_isize
- 2) * INOPB
* (fsd
.s_type
== Fs2b
? 2 : 1));
1378 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.s_tinode
);
1380 #elif defined STAT_STATFS3_OSF1 /* OSF/1 */
1384 if (statfs (file
, &fsd
, sizeof (struct statfs
)) != 0)
1387 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1389 #elif defined STAT_STATFS2_BSIZE /* glibc/Linux, 4.3BSD, SunOS 4, \
1390 Mac OS X < 10.4, FreeBSD < 5.0, \
1391 NetBSD < 3.0, OpenBSD < 4.4 */
1395 if (statfs (file
, &fsd
) < 0)
1398 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1400 #ifdef STATFS_TRUNCATES_BLOCK_COUNTS
1402 /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
1403 struct statfs are truncated to 2GB. These conditions detect that
1404 truncation, presumably without botching the 4.1.1 case, in which
1405 the values are not truncated. The correct counts are stored in
1406 undocumented spare fields. */
1407 if (fsd
.f_blocks
== 0x7fffffff / fsd
.f_bsize
&& fsd
.f_spare
[0] > 0)
1409 fsd
.f_blocks
= fsd
.f_spare
[0];
1410 fsd
.f_bfree
= fsd
.f_spare
[1];
1411 fsd
.f_bavail
= fsd
.f_spare
[2];
1413 #endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
1415 #elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
1419 if (statfs (file
, &fsd
) < 0)
1422 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_fsize
);
1424 #elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
1427 #if !defined _AIX && !defined _SEQUENT_ && !defined DOLPHIN
1428 #define f_bavail f_bfree
1433 if (statfs (file
, &fsd
, sizeof (fsd
), 0) < 0)
1436 /* Empirically, the block counts on most SVR3 and SVR3-derived
1437 systems seem to always be in terms of 512-byte blocks,
1438 no matter what value f_bsize has. */
1439 #if defined _AIX || defined _CRAY
1440 fsp
->fsu_blocksize
= PROPAGATE_ALL_ONES (fsd
.f_bsize
);
1442 fsp
->fsu_blocksize
= 512;
1447 #if (defined STAT_STATVFS || defined STAT_STATVFS64 \
1448 || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
1450 fsp
->fsu_blocks
= PROPAGATE_ALL_ONES (fsd
.f_blocks
);
1451 fsp
->fsu_bfree
= PROPAGATE_ALL_ONES (fsd
.f_bfree
);
1452 fsp
->fsu_bavail
= PROPAGATE_TOP_BIT (fsd
.f_bavail
);
1453 fsp
->fsu_bavail_top_bit_set
= EXTRACT_TOP_BIT (fsd
.f_bavail
) != 0;
1454 fsp
->fsu_files
= PROPAGATE_ALL_ONES (fsd
.f_files
);
1455 fsp
->fsu_ffree
= PROPAGATE_ALL_ONES (fsd
.f_ffree
);
1458 (void) disk
; /* avoid argument-unused warning */
1461 #endif /* HAVE_INFOMOUNT */
1463 /* --------------------------------------------------------------------------------------------- */
1464 /*** public functions ****************************************************************************/
1465 /* --------------------------------------------------------------------------------------------- */
1468 free_my_statfs (void)
1470 #ifdef HAVE_INFOMOUNT_LIST
1471 while (mc_mount_list
!= NULL
)
1473 struct mount_entry
*next
;
1475 next
= mc_mount_list
->me_next
;
1476 free_mount_entry (mc_mount_list
);
1477 mc_mount_list
= next
;
1480 mc_mount_list
= NULL
;
1481 #endif /* HAVE_INFOMOUNT_LIST */
1484 /* --------------------------------------------------------------------------------------------- */
1487 init_my_statfs (void)
1489 #ifdef HAVE_INFOMOUNT_LIST
1491 mc_mount_list
= read_file_system_list (1);
1492 #endif /* HAVE_INFOMOUNT_LIST */
1495 /* --------------------------------------------------------------------------------------------- */
1498 my_statfs (struct my_statfs
*myfs_stats
, const char *path
)
1500 #ifdef HAVE_INFOMOUNT_LIST
1502 struct mount_entry
*entry
= NULL
;
1503 struct mount_entry
*temp
= mc_mount_list
;
1504 struct fs_usage fs_use
;
1508 i
= strlen (temp
->me_mountdir
);
1509 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
1510 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == '\0'))
1515 temp
= temp
->me_next
;
1520 memset (&fs_use
, 0, sizeof (struct fs_usage
));
1521 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1523 myfs_stats
->type
= entry
->me_dev
;
1524 myfs_stats
->typename
= entry
->me_type
;
1525 myfs_stats
->mpoint
= entry
->me_mountdir
;
1526 myfs_stats
->device
= entry
->me_devname
;
1528 ((uintmax_t) (getuid ()? fs_use
.fsu_bavail
: fs_use
.fsu_bfree
) *
1529 fs_use
.fsu_blocksize
) >> 10;
1530 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1531 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1532 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1535 #endif /* HAVE_INFOMOUNT_LIST */
1537 #ifdef HAVE_INFOMOUNT_QNX
1539 ** This is the "other side" of the hack to read_file_system_list() in
1541 ** It's not the most efficient approach, but consumes less memory. It
1542 ** also accomodates QNX's ability to mount filesystems on the fly.
1544 struct mount_entry
*entry
;
1545 struct fs_usage fs_use
;
1547 entry
= read_file_system_list (0, 0);
1550 get_fs_usage (entry
->me_mountdir
, NULL
, &fs_use
);
1552 myfs_stats
->type
= entry
->me_dev
;
1553 myfs_stats
->typename
= entry
->me_type
;
1554 myfs_stats
->mpoint
= entry
->me_mountdir
;
1555 myfs_stats
->device
= entry
->me_devname
;
1557 myfs_stats
->avail
= ((uintmax_t) fs_use
.fsu_bfree
* fs_use
.fsu_blocksize
) >> 10;
1558 myfs_stats
->total
= ((uintmax_t) fs_use
.fsu_blocks
* fs_use
.fsu_blocksize
) >> 10;
1559 myfs_stats
->nfree
= (uintmax_t) fs_use
.fsu_ffree
;
1560 myfs_stats
->nodes
= (uintmax_t) fs_use
.fsu_files
;
1563 #endif /* HAVE_INFOMOUNT_QNX */
1565 myfs_stats
->type
= 0;
1566 myfs_stats
->mpoint
= "unknown";
1567 myfs_stats
->device
= "unknown";
1568 myfs_stats
->avail
= 0;
1569 myfs_stats
->total
= 0;
1570 myfs_stats
->nfree
= 0;
1571 myfs_stats
->nodes
= 0;
1575 /* --------------------------------------------------------------------------------------------- */