1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
20 #include "mountlist.h"
37 # include <sys/param.h>
41 # include <sys/mkdev.h>
42 #elif MAJOR_IN_SYSMACROS
43 # include <sys/sysmacros.h>
46 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
48 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
49 NGROUPS is used as an array dimension in ucred.h */
50 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
53 # include <sys/mount.h>
55 # if HAVE_SYS_FS_TYPES_H
56 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
58 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
59 # define FS_TYPE(Ent) ((Ent).f_fstypename)
61 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
63 #endif /* MOUNTED_GETFSSTAT */
65 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
66 also (obsolete) 4.3BSD, SunOS */
68 # include <sys/types.h>
69 # if defined __ANDROID__ /* Android */
70 /* Bionic versions from between 2014-01-09 and 2015-01-08 define MOUNTED to
71 an incorrect value; older Bionic versions don't define it at all. */
73 # define MOUNTED "/proc/mounts"
74 # elif !defined MOUNTED
75 # if defined _PATH_MOUNTED /* GNU libc */
76 # define MOUNTED _PATH_MOUNTED
78 # if defined MNT_MNTTAB /* HP-UX. */
79 # define MOUNTED MNT_MNTTAB
84 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
85 # include <sys/mount.h>
88 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
89 # include <sys/statvfs.h>
92 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
97 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
99 # include <sys/fstyp.h>
100 # include <sys/statfs.h>
103 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
104 # include <sys/mnttab.h>
107 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
108 # include <sys/mnttab.h>
111 #ifdef MOUNTED_VMOUNT /* AIX */
113 # include <sys/vfs.h>
116 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
117 # include <sys/statvfs.h>
121 #if HAVE_SYS_MNTENT_H
122 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
123 # include <sys/mntent.h>
126 #ifdef MOUNTED_GETMNTENT1
127 # if !HAVE_SETMNTENT /* Android <= 4.4 */
128 # define setmntent(fp,mode) fopen (fp, mode "e")
130 # if !HAVE_ENDMNTENT /* Android <= 4.4 */
131 # define endmntent(fp) fclose (fp)
135 #ifndef HAVE_HASMNTOPT
136 # define hasmntopt(mnt, opt) ((char *) 0)
141 # if defined __sun && defined __SVR4
142 /* Solaris defines hasmntopt(struct mnttab *, char *)
143 while it is otherwise hasmntopt(struct mnttab *, const char *). */
144 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
146 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
149 # define MNT_IGNORE(M) 0
153 # include "unlocked-io.h"
156 /* The results of opendir() in this file are not used with dirfd and fchdir,
157 therefore save some unnecessary work in fchdir.c. */
158 #ifdef GNULIB_defined_opendir
161 #ifdef GNULIB_defined_closedir
165 #define ME_DUMMY_0(Fs_name, Fs_type) \
166 (strcmp (Fs_type, "autofs") == 0 \
167 || strcmp (Fs_type, "proc") == 0 \
168 || strcmp (Fs_type, "subfs") == 0 \
169 /* for Linux 2.6/3.x */ \
170 || strcmp (Fs_type, "debugfs") == 0 \
171 || strcmp (Fs_type, "devpts") == 0 \
172 || strcmp (Fs_type, "fusectl") == 0 \
173 || strcmp (Fs_type, "mqueue") == 0 \
174 || strcmp (Fs_type, "rpc_pipefs") == 0 \
175 || strcmp (Fs_type, "sysfs") == 0 \
176 /* FreeBSD, Linux 2.4 */ \
177 || strcmp (Fs_type, "devfs") == 0 \
178 /* for NetBSD 3.0 */ \
179 || strcmp (Fs_type, "kernfs") == 0 \
181 || strcmp (Fs_type, "ignore") == 0)
183 /* Historically, we have marked as "dummy" any file system of type "none",
184 but now that programs like du need to know about bind-mounted directories,
185 we grant an exception to any with "bind" in its list of mount options.
186 I.e., those are *not* dummy entries. */
187 #ifdef MOUNTED_GETMNTENT1
188 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
189 (ME_DUMMY_0 (Fs_name, Fs_type) \
190 || (strcmp (Fs_type, "none") == 0 && !Bind))
192 # define ME_DUMMY(Fs_name, Fs_type) \
193 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
197 # include <windows.h>
198 /* Don't assume that UNICODE is not defined. */
200 # define GetDriveType GetDriveTypeA
201 # define ME_REMOTE me_remote
202 /* All cygwin mount points include ':' or start with '//'; so it
203 requires a native Windows call to determine remote disks. */
205 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
207 if (fs_name
[0] && fs_name
[1] == ':')
210 sprintf (drive
, "%c:\\", fs_name
[0]);
211 switch (GetDriveType (drive
))
213 case DRIVE_REMOVABLE
:
225 /* A file system is "remote" if its Fs_name contains a ':'
226 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
227 or if it is of type (afs or auristorfs)
228 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
229 # define ME_REMOTE(Fs_name, Fs_type) \
230 (strchr (Fs_name, ':') != NULL \
231 || ((Fs_name)[0] == '/' \
232 && (Fs_name)[1] == '/' \
233 && (strcmp (Fs_type, "smbfs") == 0 \
234 || strcmp (Fs_type, "smb3") == 0 \
235 || strcmp (Fs_type, "cifs") == 0)) \
236 || strcmp (Fs_type, "afs") == 0 \
237 || strcmp (Fs_type, "auristorfs") == 0 \
238 || strcmp ("-hosts", Fs_name) == 0)
241 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
243 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
245 fstype_to_string (short int t
)
340 fsp_to_string (const struct statfs
*fsp
)
342 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
343 return (char *) (fsp
->f_fstypename
);
345 return fstype_to_string (fsp
->f_type
);
349 #endif /* MOUNTED_GETMNTINFO */
351 #ifdef MOUNTED_VMOUNT /* AIX */
353 fstype_to_string (int t
)
357 e
= getvfsbytype (t
);
358 if (!e
|| !e
->vfsent_name
)
361 return e
->vfsent_name
;
363 #endif /* MOUNTED_VMOUNT */
366 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
368 /* Return the device number from MOUNT_OPTIONS, if possible.
369 Otherwise return (dev_t) -1. */
371 dev_from_mount_options (char const *mount_options
)
373 /* GNU/Linux allows file system implementations to define their own
374 meaning for "dev=" mount options, so don't trust the meaning
378 static char const dev_pattern
[] = ",dev=";
379 char const *devopt
= strstr (mount_options
, dev_pattern
);
383 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
385 unsigned long int dev
;
387 dev
= strtoul (optval
, &optvalend
, 16);
388 if (optval
!= optvalend
389 && (*optvalend
== '\0' || *optvalend
== ',')
390 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
391 && dev
== (dev_t
) dev
)
396 (void) mount_options
;
402 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
404 /* Unescape the paths in mount tables.
405 STR is updated in place. */
408 unescape_tab (char *str
)
411 size_t len
= strlen (str
) + 1;
412 for (i
= 0; i
< len
; i
++)
414 if (str
[i
] == '\\' && (i
+ 4 < len
)
415 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
416 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
417 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
419 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
420 (str
[i
+ 2] - '0') * 8 +
429 /* Find the next space in STR, terminate the string there in place,
430 and return that position. Otherwise return NULL. */
433 terminate_at_blank (char *str
)
435 char *s
= strchr (str
, ' ');
442 /* Return a list of the currently mounted file systems, or NULL on error.
443 Add each entry to the tail of the list so that they stay in order.
444 If NEED_FS_TYPE is true, ensure that the file system type fields in
445 the returned list are valid. Otherwise, they might not be. */
448 read_file_system_list (bool need_fs_type
)
450 struct mount_entry
*mount_list
;
451 struct mount_entry
*me
;
452 struct mount_entry
**mtail
= &mount_list
;
455 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
456 also (obsolete) 4.3BSD, SunOS */
460 # if defined __linux__ || defined __ANDROID__
461 /* Try parsing mountinfo first, as that make device IDs available.
462 Note we could use libmount routines to simplify this parsing a little
463 (and that code is in previous versions of this function), however
464 libmount depends on libselinux which pulls in many dependencies. */
465 char const *mountinfo
= "/proc/self/mountinfo";
466 fp
= fopen (mountinfo
, "re");
472 while (getline (&line
, &buf_size
, fp
) != -1)
474 unsigned int devmaj
, devmin
;
477 rc
= sscanf(line
, "%*u " /* id - discarded */
478 "%*u " /* parent - discarded */
479 "%u:%u " /* dev major:minor */
480 "%n", /* mountroot (start) */
484 if (rc
!= 2 && rc
!= 3) /* 3 if %n included in count. */
487 /* find end of MNTROOT. */
488 char *mntroot
= line
+ mntroot_s
;
489 char *blank
= terminate_at_blank (mntroot
);
493 /* find end of TARGET. */
494 char *target
= blank
+ 1;
495 blank
= terminate_at_blank (target
);
499 /* skip optional fields, terminated by " - " */
500 char *dash
= strstr (blank
+ 1, " - ");
504 /* advance past the " - " separator. */
505 char *fstype
= dash
+ 3;
506 blank
= terminate_at_blank (fstype
);
510 /* find end of SOURCE. */
511 char *source
= blank
+ 1;
512 if (! terminate_at_blank (source
))
515 /* manipulate the sub-strings in place. */
516 unescape_tab (source
);
517 unescape_tab (target
);
518 unescape_tab (mntroot
);
519 unescape_tab (fstype
);
521 me
= xmalloc (sizeof *me
);
523 me
->me_devname
= xstrdup (source
);
524 me
->me_mountdir
= xstrdup (target
);
525 me
->me_mntroot
= xstrdup (mntroot
);
526 me
->me_type
= xstrdup (fstype
);
527 me
->me_type_malloced
= 1;
528 me
->me_dev
= makedev (devmaj
, devmin
);
529 /* we pass "false" for the "Bind" option as that's only
530 significant when the Fs_type is "none" which will not be
531 the case when parsing "/proc/self/mountinfo", and only
532 applies for static /etc/mtab files. */
533 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
534 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
536 /* Add to the linked list. */
538 mtail
= &me
->me_next
;
545 int saved_errno
= errno
;
551 if (fclose (fp
) == EOF
)
554 else /* fallback to /proc/self/mounts (/etc/mtab). */
555 # endif /* __linux __ || __ANDROID__ */
558 char const *table
= MOUNTED
;
560 fp
= setmntent (table
, "r");
564 while ((mnt
= getmntent (fp
)))
566 bool bind
= hasmntopt (mnt
, "bind");
568 me
= xmalloc (sizeof *me
);
569 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
570 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
571 me
->me_mntroot
= NULL
;
572 me
->me_type
= xstrdup (mnt
->mnt_type
);
573 me
->me_type_malloced
= 1;
574 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
575 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
576 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
578 /* Add to the linked list. */
580 mtail
= &me
->me_next
;
583 if (endmntent (fp
) == 0)
587 #endif /* MOUNTED_GETMNTENT1. */
589 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
594 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
597 for (; entries
-- > 0; fsp
++)
599 char *fs_type
= fsp_to_string (fsp
);
601 me
= xmalloc (sizeof *me
);
602 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
603 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
604 me
->me_mntroot
= NULL
;
605 me
->me_type
= fs_type
;
606 me
->me_type_malloced
= 0;
607 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
608 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
609 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
611 /* Add to the linked list. */
613 mtail
= &me
->me_next
;
616 #endif /* MOUNTED_GETMNTINFO */
618 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
623 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
626 for (; entries
-- > 0; fsp
++)
628 me
= xmalloc (sizeof *me
);
629 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
630 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
631 me
->me_mntroot
= NULL
;
632 me
->me_type
= xstrdup (fsp
->f_fstypename
);
633 me
->me_type_malloced
= 1;
634 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
635 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
636 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
638 /* Add to the linked list. */
640 mtail
= &me
->me_next
;
643 #endif /* MOUNTED_GETMNTINFO2 */
645 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
647 /* The next_dev() and fs_stat_dev() system calls give the list of
648 all file systems, including the information returned by statvfs()
649 (fs type, total blocks, free blocks etc.), but without the mount
650 point. But on BeOS all file systems except / are mounted in the
651 rootfs, directly under /.
652 The directory name of the mount point is often, but not always,
653 identical to the volume name of the device.
654 We therefore get the list of subdirectories of /, and the list
655 of all file systems, and match the two lists. */
663 struct rootdir_entry
*next
;
665 struct rootdir_entry
*rootdir_list
;
666 struct rootdir_entry
**rootdir_tail
;
671 /* All volumes are mounted in the rootfs, directly under /. */
673 rootdir_tail
= &rootdir_list
;
674 dirp
= opendir ("/");
679 while ((d
= readdir (dirp
)) != NULL
)
684 if (strcmp (d
->d_name
, "..") == 0)
687 if (strcmp (d
->d_name
, ".") == 0)
688 name
= xstrdup ("/");
691 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
693 strcpy (name
+ 1, d
->d_name
);
696 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
698 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
700 re
->dev
= statbuf
.st_dev
;
701 re
->ino
= statbuf
.st_ino
;
703 /* Add to the linked list. */
705 rootdir_tail
= &re
->next
;
712 *rootdir_tail
= NULL
;
714 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
715 if (fs_stat_dev (dev
, &fi
) >= 0)
717 /* Note: fi.dev == dev. */
718 struct rootdir_entry
*re
;
720 for (re
= rootdir_list
; re
; re
= re
->next
)
721 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
724 me
= xmalloc (sizeof *me
);
725 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
726 ? fi
.device_name
: fi
.fsh_name
);
727 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
728 me
->me_mntroot
= NULL
;
729 me
->me_type
= xstrdup (fi
.fsh_name
);
730 me
->me_type_malloced
= 1;
733 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
735 /* Add to the linked list. */
737 mtail
= &me
->me_next
;
741 while (rootdir_list
!= NULL
)
743 struct rootdir_entry
*re
= rootdir_list
;
744 rootdir_list
= re
->next
;
749 #endif /* MOUNTED_FS_STAT_DEV */
751 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
755 struct statfs
*stats
;
757 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
760 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
763 bufsize
= (1 + numsys
) * sizeof *stats
;
764 stats
= xmalloc (bufsize
);
765 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
773 for (counter
= 0; counter
< numsys
; counter
++)
775 me
= xmalloc (sizeof *me
);
776 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
777 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
778 me
->me_mntroot
= NULL
;
779 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
780 me
->me_type_malloced
= 1;
781 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
782 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
783 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
785 /* Add to the linked list. */
787 mtail
= &me
->me_next
;
792 #endif /* MOUNTED_GETFSSTAT */
794 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
797 char *table
= "/etc/mnttab";
800 fp
= fopen (table
, "re");
804 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
806 me
= xmalloc (sizeof *me
);
807 me
->me_devname
= xstrdup (mnt
.mt_dev
);
808 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
809 me
->me_mntroot
= NULL
;
810 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
812 me
->me_type_malloced
= 0;
816 char typebuf
[FSTYPSZ
];
818 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
819 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
821 me
->me_type
= xstrdup (typebuf
);
822 me
->me_type_malloced
= 1;
825 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
826 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
828 /* Add to the linked list. */
830 mtail
= &me
->me_next
;
835 /* The last fread() call must have failed. */
836 int saved_errno
= errno
;
842 if (fclose (fp
) == EOF
)
845 #endif /* MOUNTED_FREAD_FSTYP. */
847 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
849 struct extmnttab mnt
;
850 const char *table
= MNTTAB
;
854 /* No locking is needed, because the contents of /etc/mnttab is generated
858 fp
= fopen (table
, "re");
863 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
865 me
= xmalloc (sizeof *me
);
866 me
->me_devname
= xstrdup (mnt
.mnt_special
);
867 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
868 me
->me_mntroot
= NULL
;
869 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
870 me
->me_type_malloced
= 1;
871 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
872 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
873 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
875 /* Add to the linked list. */
877 mtail
= &me
->me_next
;
880 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
881 /* Here ret = -1 means success, ret >= 0 means failure. */
890 #endif /* MOUNTED_GETEXTMNTENT */
892 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
895 const char *table
= MNTTAB
;
900 # if defined F_RDLCK && defined F_SETLKW
901 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
902 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
903 for this file name, we should use their macro name instead.
904 (Why not just lock MNTTAB directly? We don't know.) */
906 # define MNTTAB_LOCK "/etc/.mnttab.lock"
908 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
| O_CLOEXEC
);
912 flock
.l_type
= F_RDLCK
;
913 flock
.l_whence
= SEEK_SET
;
916 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
919 int saved_errno
= errno
;
925 else if (errno
!= ENOENT
)
930 fp
= fopen (table
, "re");
935 while ((ret
= getmntent (fp
, &mnt
)) == 0)
937 me
= xmalloc (sizeof *me
);
938 me
->me_devname
= xstrdup (mnt
.mnt_special
);
939 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
940 me
->me_mntroot
= NULL
;
941 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
942 me
->me_type_malloced
= 1;
943 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
944 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
945 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
947 /* Add to the linked list. */
949 mtail
= &me
->me_next
;
952 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
953 /* Here ret = -1 means success, ret >= 0 means failure. */
956 if (0 <= lockfd
&& close (lockfd
) != 0)
965 #endif /* MOUNTED_GETMNTENT2. */
967 #ifdef MOUNTED_VMOUNT /* AIX */
976 /* Ask how many bytes to allocate for the mounted file system info. */
978 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
980 entries
= xmalloc (bufsize
);
982 /* Get the list of mounted file systems. */
983 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
986 int saved_errno
= errno
;
992 for (i
= 0, thisent
= entries
;
994 i
++, thisent
+= vmp
->vmt_length
)
996 char *options
, *ignore
;
998 vmp
= (struct vmount
*) thisent
;
999 me
= xmalloc (sizeof *me
);
1000 if (vmp
->vmt_flags
& MNT_REMOTE
)
1005 /* Prepend the remote dirname. */
1006 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1007 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1008 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1009 strcpy (me
->me_devname
, host
);
1010 strcat (me
->me_devname
, ":");
1011 strcat (me
->me_devname
, dir
);
1016 me
->me_devname
= xstrdup (thisent
+
1017 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1019 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1020 me
->me_mntroot
= NULL
;
1021 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1022 me
->me_type_malloced
= 1;
1023 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1024 ignore
= strstr (options
, "ignore");
1025 me
->me_dummy
= (ignore
1026 && (ignore
== options
|| ignore
[-1] == ',')
1027 && (ignore
[sizeof "ignore" - 1] == ','
1028 || ignore
[sizeof "ignore" - 1] == '\0'));
1029 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1031 /* Add to the linked list. */
1033 mtail
= &me
->me_next
;
1037 #endif /* MOUNTED_VMOUNT. */
1039 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1041 DIR *dirp
= opendir ("/dev/fs");
1042 char node
[9 + NAME_MAX
];
1045 goto free_then_fail
;
1050 struct dirent entry
;
1051 struct dirent
*result
;
1053 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1054 marked obsolescent in glibc. Use readdir instead. */
1055 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1058 strcpy (node
, "/dev/fs/");
1059 strcat (node
, entry
.d_name
);
1061 if (statvfs (node
, &dev
) == 0)
1063 me
= xmalloc (sizeof *me
);
1064 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1065 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1066 me
->me_mntroot
= NULL
;
1067 me
->me_type
= xstrdup (dev
.f_fstypename
);
1068 me
->me_type_malloced
= 1;
1069 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1070 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1071 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1073 /* Add to the linked list. */
1075 mtail
= &me
->me_next
;
1080 #endif /* MOUNTED_INTERIX_STATVFS */
1086 free_then_fail
: _GL_UNUSED_LABEL
1088 int saved_errno
= errno
;
1093 me
= mount_list
->me_next
;
1094 free_mount_entry (mount_list
);
1098 errno
= saved_errno
;
1103 /* Free a mount entry as returned from read_file_system_list (). */
1105 void free_mount_entry (struct mount_entry
*me
)
1107 free (me
->me_devname
);
1108 free (me
->me_mountdir
);
1109 free (me
->me_mntroot
);
1110 if (me
->me_type_malloced
)