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)
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 # define ME_REMOTE me_remote
199 /* All cygwin mount points include ':' or start with '//'; so it
200 requires a native Windows call to determine remote disks. */
202 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
204 if (fs_name
[0] && fs_name
[1] == ':')
207 sprintf (drive
, "%c:\\", fs_name
[0]);
208 switch (GetDriveType (drive
))
210 case DRIVE_REMOVABLE
:
222 /* A file system is "remote" if its Fs_name contains a ':'
223 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
224 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
225 # define ME_REMOTE(Fs_name, Fs_type) \
226 (strchr (Fs_name, ':') != NULL \
227 || ((Fs_name)[0] == '/' \
228 && (Fs_name)[1] == '/' \
229 && (strcmp (Fs_type, "smbfs") == 0 \
230 || strcmp (Fs_type, "cifs") == 0)) \
231 || (strcmp("-hosts", Fs_name) == 0))
234 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
236 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
238 fstype_to_string (short int t
)
333 fsp_to_string (const struct statfs
*fsp
)
335 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
336 return (char *) (fsp
->f_fstypename
);
338 return fstype_to_string (fsp
->f_type
);
342 #endif /* MOUNTED_GETMNTINFO */
344 #ifdef MOUNTED_VMOUNT /* AIX */
346 fstype_to_string (int t
)
350 e
= getvfsbytype (t
);
351 if (!e
|| !e
->vfsent_name
)
354 return e
->vfsent_name
;
356 #endif /* MOUNTED_VMOUNT */
359 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
361 /* Return the device number from MOUNT_OPTIONS, if possible.
362 Otherwise return (dev_t) -1. */
364 dev_from_mount_options (char const *mount_options
)
366 /* GNU/Linux allows file system implementations to define their own
367 meaning for "dev=" mount options, so don't trust the meaning
371 static char const dev_pattern
[] = ",dev=";
372 char const *devopt
= strstr (mount_options
, dev_pattern
);
376 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
378 unsigned long int dev
;
380 dev
= strtoul (optval
, &optvalend
, 16);
381 if (optval
!= optvalend
382 && (*optvalend
== '\0' || *optvalend
== ',')
383 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
384 && dev
== (dev_t
) dev
)
389 (void) mount_options
;
395 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
397 /* Unescape the paths in mount tables.
398 STR is updated in place. */
401 unescape_tab (char *str
)
404 size_t len
= strlen (str
) + 1;
405 for (i
= 0; i
< len
; i
++)
407 if (str
[i
] == '\\' && (i
+ 4 < len
)
408 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
409 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
410 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
412 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
413 (str
[i
+ 2] - '0') * 8 +
422 /* Find the next space in STR, terminate the string there in place,
423 and return that position. Otherwise return NULL. */
426 terminate_at_blank (char *str
)
428 char *s
= strchr (str
, ' ');
435 /* Return a list of the currently mounted file systems, or NULL on error.
436 Add each entry to the tail of the list so that they stay in order.
437 If NEED_FS_TYPE is true, ensure that the file system type fields in
438 the returned list are valid. Otherwise, they might not be. */
441 read_file_system_list (bool need_fs_type
)
443 struct mount_entry
*mount_list
;
444 struct mount_entry
*me
;
445 struct mount_entry
**mtail
= &mount_list
;
448 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
449 also (obsolete) 4.3BSD, SunOS */
453 # if defined __linux__ || defined __ANDROID__
454 /* Try parsing mountinfo first, as that make device IDs available.
455 Note we could use libmount routines to simplify this parsing a little
456 (and that code is in previous versions of this function), however
457 libmount depends on libselinux which pulls in many dependencies. */
458 char const *mountinfo
= "/proc/self/mountinfo";
459 fp
= fopen (mountinfo
, "r");
465 while (getline (&line
, &buf_size
, fp
) != -1)
467 unsigned int devmaj
, devmin
;
470 rc
= sscanf(line
, "%*u " /* id - discarded */
471 "%*u " /* parent - discarded */
472 "%u:%u " /* dev major:minor */
473 "%n", /* mountroot (start) */
477 if (rc
!= 2 && rc
!= 3) /* 3 if %n included in count. */
480 /* find end of MNTROOT. */
481 char *mntroot
= line
+ mntroot_s
;
482 char *blank
= terminate_at_blank (mntroot
);
486 /* find end of TARGET. */
487 char *target
= blank
+ 1;
488 blank
= terminate_at_blank (target
);
492 /* skip optional fields, terminated by " - " */
493 char *dash
= strstr (blank
+ 1, " - ");
497 /* advance past the " - " separator. */
498 char *fstype
= dash
+ 3;
499 blank
= terminate_at_blank (fstype
);
503 /* find end of SOURCE. */
504 char *source
= blank
+ 1;
505 if (! terminate_at_blank (source
))
508 /* manipulate the sub-strings in place. */
509 unescape_tab (source
);
510 unescape_tab (target
);
511 unescape_tab (mntroot
);
512 unescape_tab (fstype
);
514 me
= xmalloc (sizeof *me
);
516 me
->me_devname
= xstrdup (source
);
517 me
->me_mountdir
= xstrdup (target
);
518 me
->me_mntroot
= xstrdup (mntroot
);
519 me
->me_type
= xstrdup (fstype
);
520 me
->me_type_malloced
= 1;
521 me
->me_dev
= makedev (devmaj
, devmin
);
522 /* we pass "false" for the "Bind" option as that's only
523 significant when the Fs_type is "none" which will not be
524 the case when parsing "/proc/self/mountinfo", and only
525 applies for static /etc/mtab files. */
526 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
527 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
529 /* Add to the linked list. */
531 mtail
= &me
->me_next
;
538 int saved_errno
= errno
;
544 if (fclose (fp
) == EOF
)
547 else /* fallback to /proc/self/mounts (/etc/mtab). */
548 # endif /* __linux __ || __ANDROID__ */
551 char const *table
= MOUNTED
;
553 fp
= setmntent (table
, "r");
557 while ((mnt
= getmntent (fp
)))
559 bool bind
= hasmntopt (mnt
, "bind");
561 me
= xmalloc (sizeof *me
);
562 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
563 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
564 me
->me_mntroot
= NULL
;
565 me
->me_type
= xstrdup (mnt
->mnt_type
);
566 me
->me_type_malloced
= 1;
567 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
568 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
569 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
571 /* Add to the linked list. */
573 mtail
= &me
->me_next
;
576 if (endmntent (fp
) == 0)
580 #endif /* MOUNTED_GETMNTENT1. */
582 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
587 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
590 for (; entries
-- > 0; fsp
++)
592 char *fs_type
= fsp_to_string (fsp
);
594 me
= xmalloc (sizeof *me
);
595 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
596 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
597 me
->me_mntroot
= NULL
;
598 me
->me_type
= fs_type
;
599 me
->me_type_malloced
= 0;
600 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
601 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
602 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
604 /* Add to the linked list. */
606 mtail
= &me
->me_next
;
609 #endif /* MOUNTED_GETMNTINFO */
611 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
616 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
619 for (; entries
-- > 0; fsp
++)
621 me
= xmalloc (sizeof *me
);
622 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
623 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
624 me
->me_mntroot
= NULL
;
625 me
->me_type
= xstrdup (fsp
->f_fstypename
);
626 me
->me_type_malloced
= 1;
627 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
628 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
629 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
631 /* Add to the linked list. */
633 mtail
= &me
->me_next
;
636 #endif /* MOUNTED_GETMNTINFO2 */
638 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
640 /* The next_dev() and fs_stat_dev() system calls give the list of
641 all file systems, including the information returned by statvfs()
642 (fs type, total blocks, free blocks etc.), but without the mount
643 point. But on BeOS all file systems except / are mounted in the
644 rootfs, directly under /.
645 The directory name of the mount point is often, but not always,
646 identical to the volume name of the device.
647 We therefore get the list of subdirectories of /, and the list
648 of all file systems, and match the two lists. */
656 struct rootdir_entry
*next
;
658 struct rootdir_entry
*rootdir_list
;
659 struct rootdir_entry
**rootdir_tail
;
664 /* All volumes are mounted in the rootfs, directly under /. */
666 rootdir_tail
= &rootdir_list
;
667 dirp
= opendir ("/");
672 while ((d
= readdir (dirp
)) != NULL
)
677 if (strcmp (d
->d_name
, "..") == 0)
680 if (strcmp (d
->d_name
, ".") == 0)
681 name
= xstrdup ("/");
684 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
686 strcpy (name
+ 1, d
->d_name
);
689 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
691 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
693 re
->dev
= statbuf
.st_dev
;
694 re
->ino
= statbuf
.st_ino
;
696 /* Add to the linked list. */
698 rootdir_tail
= &re
->next
;
705 *rootdir_tail
= NULL
;
707 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
708 if (fs_stat_dev (dev
, &fi
) >= 0)
710 /* Note: fi.dev == dev. */
711 struct rootdir_entry
*re
;
713 for (re
= rootdir_list
; re
; re
= re
->next
)
714 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
717 me
= xmalloc (sizeof *me
);
718 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
719 ? fi
.device_name
: fi
.fsh_name
);
720 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
721 me
->me_mntroot
= NULL
;
722 me
->me_type
= xstrdup (fi
.fsh_name
);
723 me
->me_type_malloced
= 1;
726 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
728 /* Add to the linked list. */
730 mtail
= &me
->me_next
;
734 while (rootdir_list
!= NULL
)
736 struct rootdir_entry
*re
= rootdir_list
;
737 rootdir_list
= re
->next
;
742 #endif /* MOUNTED_FS_STAT_DEV */
744 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
748 struct statfs
*stats
;
750 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
753 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
756 bufsize
= (1 + numsys
) * sizeof *stats
;
757 stats
= xmalloc (bufsize
);
758 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
766 for (counter
= 0; counter
< numsys
; counter
++)
768 me
= xmalloc (sizeof *me
);
769 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
770 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
771 me
->me_mntroot
= NULL
;
772 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
773 me
->me_type_malloced
= 1;
774 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
775 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
776 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
778 /* Add to the linked list. */
780 mtail
= &me
->me_next
;
785 #endif /* MOUNTED_GETFSSTAT */
787 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
790 char *table
= "/etc/mnttab";
793 fp
= fopen (table
, "r");
797 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
799 me
= xmalloc (sizeof *me
);
800 me
->me_devname
= xstrdup (mnt
.mt_dev
);
801 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
802 me
->me_mntroot
= NULL
;
803 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
805 me
->me_type_malloced
= 0;
809 char typebuf
[FSTYPSZ
];
811 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
812 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
814 me
->me_type
= xstrdup (typebuf
);
815 me
->me_type_malloced
= 1;
818 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
819 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
821 /* Add to the linked list. */
823 mtail
= &me
->me_next
;
828 /* The last fread() call must have failed. */
829 int saved_errno
= errno
;
835 if (fclose (fp
) == EOF
)
838 #endif /* MOUNTED_FREAD_FSTYP. */
840 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
842 struct extmnttab mnt
;
843 const char *table
= MNTTAB
;
847 /* No locking is needed, because the contents of /etc/mnttab is generated
851 fp
= fopen (table
, "r");
856 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
858 me
= xmalloc (sizeof *me
);
859 me
->me_devname
= xstrdup (mnt
.mnt_special
);
860 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
861 me
->me_mntroot
= NULL
;
862 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
863 me
->me_type_malloced
= 1;
864 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
865 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
866 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
868 /* Add to the linked list. */
870 mtail
= &me
->me_next
;
873 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
874 /* Here ret = -1 means success, ret >= 0 means failure. */
883 #endif /* MOUNTED_GETEXTMNTENT */
885 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
888 const char *table
= MNTTAB
;
893 # if defined F_RDLCK && defined F_SETLKW
894 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
895 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
896 for this file name, we should use their macro name instead.
897 (Why not just lock MNTTAB directly? We don't know.) */
899 # define MNTTAB_LOCK "/etc/.mnttab.lock"
901 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
905 flock
.l_type
= F_RDLCK
;
906 flock
.l_whence
= SEEK_SET
;
909 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
912 int saved_errno
= errno
;
918 else if (errno
!= ENOENT
)
923 fp
= fopen (table
, "r");
928 while ((ret
= getmntent (fp
, &mnt
)) == 0)
930 me
= xmalloc (sizeof *me
);
931 me
->me_devname
= xstrdup (mnt
.mnt_special
);
932 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
933 me
->me_mntroot
= NULL
;
934 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
935 me
->me_type_malloced
= 1;
936 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
937 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
938 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
940 /* Add to the linked list. */
942 mtail
= &me
->me_next
;
945 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
946 /* Here ret = -1 means success, ret >= 0 means failure. */
949 if (0 <= lockfd
&& close (lockfd
) != 0)
958 #endif /* MOUNTED_GETMNTENT2. */
960 #ifdef MOUNTED_VMOUNT /* AIX */
969 /* Ask how many bytes to allocate for the mounted file system info. */
971 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
973 entries
= xmalloc (bufsize
);
975 /* Get the list of mounted file systems. */
976 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
979 int saved_errno
= errno
;
985 for (i
= 0, thisent
= entries
;
987 i
++, thisent
+= vmp
->vmt_length
)
989 char *options
, *ignore
;
991 vmp
= (struct vmount
*) thisent
;
992 me
= xmalloc (sizeof *me
);
993 if (vmp
->vmt_flags
& MNT_REMOTE
)
998 /* Prepend the remote dirname. */
999 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1000 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1001 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1002 strcpy (me
->me_devname
, host
);
1003 strcat (me
->me_devname
, ":");
1004 strcat (me
->me_devname
, dir
);
1009 me
->me_devname
= xstrdup (thisent
+
1010 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1012 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1013 me
->me_mntroot
= NULL
;
1014 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1015 me
->me_type_malloced
= 1;
1016 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1017 ignore
= strstr (options
, "ignore");
1018 me
->me_dummy
= (ignore
1019 && (ignore
== options
|| ignore
[-1] == ',')
1020 && (ignore
[sizeof "ignore" - 1] == ','
1021 || ignore
[sizeof "ignore" - 1] == '\0'));
1022 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1024 /* Add to the linked list. */
1026 mtail
= &me
->me_next
;
1030 #endif /* MOUNTED_VMOUNT. */
1032 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1034 DIR *dirp
= opendir ("/dev/fs");
1035 char node
[9 + NAME_MAX
];
1038 goto free_then_fail
;
1043 struct dirent entry
;
1044 struct dirent
*result
;
1046 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1047 marked obsolescent in glibc. Use readdir instead. */
1048 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1051 strcpy (node
, "/dev/fs/");
1052 strcat (node
, entry
.d_name
);
1054 if (statvfs (node
, &dev
) == 0)
1056 me
= xmalloc (sizeof *me
);
1057 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1058 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1059 me
->me_mntroot
= NULL
;
1060 me
->me_type
= xstrdup (dev
.f_fstypename
);
1061 me
->me_type_malloced
= 1;
1062 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1063 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1064 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1066 /* Add to the linked list. */
1068 mtail
= &me
->me_next
;
1073 #endif /* MOUNTED_INTERIX_STATVFS */
1079 free_then_fail
: _GL_UNUSED_LABEL
1081 int saved_errno
= errno
;
1086 me
= mount_list
->me_next
;
1087 free_mount_entry (mount_list
);
1091 errno
= saved_errno
;
1096 /* Free a mount entry as returned from read_file_system_list (). */
1098 void free_mount_entry (struct mount_entry
*me
)
1100 free (me
->me_devname
);
1101 free (me
->me_mountdir
);
1102 free (me
->me_mntroot
);
1103 if (me
->me_type_malloced
)