1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2018 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>
70 # if defined _PATH_MOUNTED /* GNU libc */
71 # define MOUNTED _PATH_MOUNTED
73 # if defined MNT_MNTTAB /* HP-UX. */
74 # define MOUNTED MNT_MNTTAB
79 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
80 # include <sys/mount.h>
83 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
84 # include <sys/statvfs.h>
87 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
88 # include <sys/mount.h>
89 # include <sys/fs_types.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_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
107 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
108 # include <sys/mnttab.h>
111 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
112 # include <sys/mnttab.h>
115 #ifdef MOUNTED_VMOUNT /* AIX */
117 # include <sys/vfs.h>
120 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
121 # include <sys/statvfs.h>
125 #if HAVE_SYS_MNTENT_H
126 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
127 # include <sys/mntent.h>
130 #ifndef HAVE_HASMNTOPT
131 # define hasmntopt(mnt, opt) ((char *) 0)
136 # if defined __sun && defined __SVR4
137 /* Solaris defines hasmntopt(struct mnttab *, char *)
138 while it is otherwise hasmntopt(struct mnttab *, const char *). */
139 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
141 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
144 # define MNT_IGNORE(M) 0
148 # include "unlocked-io.h"
151 /* The results of opendir() in this file are not used with dirfd and fchdir,
152 therefore save some unnecessary work in fchdir.c. */
153 #ifdef GNULIB_defined_opendir
156 #ifdef GNULIB_defined_closedir
160 #define ME_DUMMY_0(Fs_name, Fs_type) \
161 (strcmp (Fs_type, "autofs") == 0 \
162 || strcmp (Fs_type, "proc") == 0 \
163 || strcmp (Fs_type, "subfs") == 0 \
164 /* for Linux 2.6/3.x */ \
165 || strcmp (Fs_type, "debugfs") == 0 \
166 || strcmp (Fs_type, "devpts") == 0 \
167 || strcmp (Fs_type, "fusectl") == 0 \
168 || strcmp (Fs_type, "mqueue") == 0 \
169 || strcmp (Fs_type, "rpc_pipefs") == 0 \
170 || strcmp (Fs_type, "sysfs") == 0 \
171 /* FreeBSD, Linux 2.4 */ \
172 || strcmp (Fs_type, "devfs") == 0 \
173 /* for NetBSD 3.0 */ \
174 || strcmp (Fs_type, "kernfs") == 0 \
176 || strcmp (Fs_type, "ignore") == 0)
178 /* Historically, we have marked as "dummy" any file system of type "none",
179 but now that programs like du need to know about bind-mounted directories,
180 we grant an exception to any with "bind" in its list of mount options.
181 I.e., those are *not* dummy entries. */
182 #ifdef MOUNTED_GETMNTENT1
183 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
184 (ME_DUMMY_0 (Fs_name, Fs_type) \
185 || (strcmp (Fs_type, "none") == 0 && !Bind))
187 # define ME_DUMMY(Fs_name, Fs_type) \
188 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
192 # include <windows.h>
193 # define ME_REMOTE me_remote
194 /* All cygwin mount points include ':' or start with '//'; so it
195 requires a native Windows call to determine remote disks. */
197 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
199 if (fs_name
[0] && fs_name
[1] == ':')
202 sprintf (drive
, "%c:\\", fs_name
[0]);
203 switch (GetDriveType (drive
))
205 case DRIVE_REMOVABLE
:
217 /* A file system is "remote" if its Fs_name contains a ':'
218 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
219 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
220 # define ME_REMOTE(Fs_name, Fs_type) \
221 (strchr (Fs_name, ':') != NULL \
222 || ((Fs_name)[0] == '/' \
223 && (Fs_name)[1] == '/' \
224 && (strcmp (Fs_type, "smbfs") == 0 \
225 || strcmp (Fs_type, "cifs") == 0)) \
226 || (strcmp("-hosts", Fs_name) == 0))
229 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
231 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
233 fstype_to_string (short int t
)
328 fsp_to_string (const struct statfs
*fsp
)
330 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
331 return (char *) (fsp
->f_fstypename
);
333 return fstype_to_string (fsp
->f_type
);
337 #endif /* MOUNTED_GETMNTINFO */
339 #ifdef MOUNTED_VMOUNT /* AIX */
341 fstype_to_string (int t
)
345 e
= getvfsbytype (t
);
346 if (!e
|| !e
->vfsent_name
)
349 return e
->vfsent_name
;
351 #endif /* MOUNTED_VMOUNT */
354 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
356 /* Return the device number from MOUNT_OPTIONS, if possible.
357 Otherwise return (dev_t) -1. */
359 dev_from_mount_options (char const *mount_options
)
361 /* GNU/Linux allows file system implementations to define their own
362 meaning for "dev=" mount options, so don't trust the meaning
366 static char const dev_pattern
[] = ",dev=";
367 char const *devopt
= strstr (mount_options
, dev_pattern
);
371 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
373 unsigned long int dev
;
375 dev
= strtoul (optval
, &optvalend
, 16);
376 if (optval
!= optvalend
377 && (*optvalend
== '\0' || *optvalend
== ',')
378 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
379 && dev
== (dev_t
) dev
)
384 (void) mount_options
;
390 #if defined MOUNTED_GETMNTENT1 && defined __linux__ /* GNU/Linux, Android */
392 /* Unescape the paths in mount tables.
393 STR is updated in place. */
396 unescape_tab (char *str
)
399 size_t len
= strlen (str
) + 1;
400 for (i
= 0; i
< len
; i
++)
402 if (str
[i
] == '\\' && (i
+ 4 < len
)
403 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
404 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
405 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
407 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
408 (str
[i
+ 2] - '0') * 8 +
418 /* Return a list of the currently mounted file systems, or NULL on error.
419 Add each entry to the tail of the list so that they stay in order.
420 If NEED_FS_TYPE is true, ensure that the file system type fields in
421 the returned list are valid. Otherwise, they might not be. */
424 read_file_system_list (bool need_fs_type
)
426 struct mount_entry
*mount_list
;
427 struct mount_entry
*me
;
428 struct mount_entry
**mtail
= &mount_list
;
431 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
433 struct tabmntent
*mntlist
, *p
;
436 /* the third and fourth arguments could be used to filter mounts,
437 but Crays doesn't seem to have any mounts that we want to
438 remove. Specifically, automount create normal NFS mounts.
441 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
443 for (p
= mntlist
; p
; p
= p
->next
)
446 me
= xmalloc (sizeof *me
);
447 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
448 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
449 me
->me_mntroot
= NULL
;
450 me
->me_type
= xstrdup (mnt
->mnt_type
);
451 me
->me_type_malloced
= 1;
452 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
453 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
456 mtail
= &me
->me_next
;
458 freemntlist (mntlist
);
462 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
463 also (obsolete) 4.3BSD, SunOS */
468 /* Try parsing mountinfo first, as that make device IDs available.
469 Note we could use libmount routines to simplify this parsing a little
470 (and that code is in previous versions of this function), however
471 libmount depends on libselinux which pulls in many dependencies. */
472 char const *mountinfo
= "/proc/self/mountinfo";
473 fp
= fopen (mountinfo
, "r");
479 while (getline (&line
, &buf_size
, fp
) != -1)
481 unsigned int devmaj
, devmin
;
482 int target_s
, target_e
, type_s
, type_e
;
483 int source_s
, source_e
, mntroot_s
, mntroot_e
;
488 rc
= sscanf(line
, "%*u " /* id - discarded */
489 "%*u " /* parent - discarded */
490 "%u:%u " /* dev major:minor */
491 "%n%*s%n " /* mountroot */
492 "%n%*s%n" /* target, start and end */
493 "%c", /* more data... */
495 &mntroot_s
, &mntroot_e
,
496 &target_s
, &target_e
,
499 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
502 /* skip optional fields, terminated by " - " */
503 dash
= strstr (line
+ target_e
, " - ");
507 rc
= sscanf(dash
, " - "
508 "%n%*s%n " /* FS type, start and end */
509 "%n%*s%n " /* source, start and end */
510 "%c", /* more data... */
512 &source_s
, &source_e
,
514 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
517 /* manipulate the sub-strings in place. */
518 line
[mntroot_e
] = '\0';
519 line
[target_e
] = '\0';
521 dash
[source_e
] = '\0';
522 unescape_tab (dash
+ source_s
);
523 unescape_tab (line
+ target_s
);
524 unescape_tab (line
+ mntroot_s
);
526 me
= xmalloc (sizeof *me
);
528 me
->me_devname
= xstrdup (dash
+ source_s
);
529 me
->me_mountdir
= xstrdup (line
+ target_s
);
530 me
->me_mntroot
= xstrdup (line
+ mntroot_s
);
531 me
->me_type
= xstrdup (dash
+ type_s
);
532 me
->me_type_malloced
= 1;
533 me
->me_dev
= makedev (devmaj
, devmin
);
534 /* we pass "false" for the "Bind" option as that's only
535 significant when the Fs_type is "none" which will not be
536 the case when parsing "/proc/self/mountinfo", and only
537 applies for static /etc/mtab files. */
538 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
539 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
541 /* Add to the linked list. */
543 mtail
= &me
->me_next
;
550 int saved_errno
= errno
;
556 if (fclose (fp
) == EOF
)
559 else /* fallback to /proc/self/mounts (/etc/mtab). */
560 # endif /* __linux __ */
563 char const *table
= MOUNTED
;
565 fp
= setmntent (table
, "r");
569 while ((mnt
= getmntent (fp
)))
571 bool bind
= hasmntopt (mnt
, "bind");
573 me
= xmalloc (sizeof *me
);
574 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
575 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
576 me
->me_mntroot
= NULL
;
577 me
->me_type
= xstrdup (mnt
->mnt_type
);
578 me
->me_type_malloced
= 1;
579 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
580 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
581 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
583 /* Add to the linked list. */
585 mtail
= &me
->me_next
;
588 if (endmntent (fp
) == 0)
592 #endif /* MOUNTED_GETMNTENT1. */
594 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
599 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
602 for (; entries
-- > 0; fsp
++)
604 char *fs_type
= fsp_to_string (fsp
);
606 me
= xmalloc (sizeof *me
);
607 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
608 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
609 me
->me_mntroot
= NULL
;
610 me
->me_type
= fs_type
;
611 me
->me_type_malloced
= 0;
612 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
613 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
614 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
616 /* Add to the linked list. */
618 mtail
= &me
->me_next
;
621 #endif /* MOUNTED_GETMNTINFO */
623 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
628 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
631 for (; entries
-- > 0; fsp
++)
633 me
= xmalloc (sizeof *me
);
634 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
635 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
636 me
->me_mntroot
= NULL
;
637 me
->me_type
= xstrdup (fsp
->f_fstypename
);
638 me
->me_type_malloced
= 1;
639 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
640 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
641 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
643 /* Add to the linked list. */
645 mtail
= &me
->me_next
;
648 #endif /* MOUNTED_GETMNTINFO2 */
650 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
657 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
660 me
= xmalloc (sizeof *me
);
661 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
662 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
663 me
->me_mntroot
= NULL
;
664 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
665 me
->me_type_malloced
= 0;
666 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
667 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
668 me
->me_dev
= fsd
.fd_req
.dev
;
670 /* Add to the linked list. */
672 mtail
= &me
->me_next
;
677 #endif /* MOUNTED_GETMNT. */
679 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
681 /* The next_dev() and fs_stat_dev() system calls give the list of
682 all file systems, including the information returned by statvfs()
683 (fs type, total blocks, free blocks etc.), but without the mount
684 point. But on BeOS all file systems except / are mounted in the
685 rootfs, directly under /.
686 The directory name of the mount point is often, but not always,
687 identical to the volume name of the device.
688 We therefore get the list of subdirectories of /, and the list
689 of all file systems, and match the two lists. */
697 struct rootdir_entry
*next
;
699 struct rootdir_entry
*rootdir_list
;
700 struct rootdir_entry
**rootdir_tail
;
705 /* All volumes are mounted in the rootfs, directly under /. */
707 rootdir_tail
= &rootdir_list
;
708 dirp
= opendir ("/");
713 while ((d
= readdir (dirp
)) != NULL
)
718 if (strcmp (d
->d_name
, "..") == 0)
721 if (strcmp (d
->d_name
, ".") == 0)
722 name
= xstrdup ("/");
725 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
727 strcpy (name
+ 1, d
->d_name
);
730 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
732 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
734 re
->dev
= statbuf
.st_dev
;
735 re
->ino
= statbuf
.st_ino
;
737 /* Add to the linked list. */
739 rootdir_tail
= &re
->next
;
746 *rootdir_tail
= NULL
;
748 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
749 if (fs_stat_dev (dev
, &fi
) >= 0)
751 /* Note: fi.dev == dev. */
752 struct rootdir_entry
*re
;
754 for (re
= rootdir_list
; re
; re
= re
->next
)
755 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
758 me
= xmalloc (sizeof *me
);
759 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
760 ? fi
.device_name
: fi
.fsh_name
);
761 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
762 me
->me_mntroot
= NULL
;
763 me
->me_type
= xstrdup (fi
.fsh_name
);
764 me
->me_type_malloced
= 1;
767 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
769 /* Add to the linked list. */
771 mtail
= &me
->me_next
;
775 while (rootdir_list
!= NULL
)
777 struct rootdir_entry
*re
= rootdir_list
;
778 rootdir_list
= re
->next
;
783 #endif /* MOUNTED_FS_STAT_DEV */
785 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
789 struct statfs
*stats
;
791 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
794 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
797 bufsize
= (1 + numsys
) * sizeof *stats
;
798 stats
= xmalloc (bufsize
);
799 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
807 for (counter
= 0; counter
< numsys
; counter
++)
809 me
= xmalloc (sizeof *me
);
810 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
811 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
812 me
->me_mntroot
= NULL
;
813 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
814 me
->me_type_malloced
= 1;
815 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
816 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
817 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
819 /* Add to the linked list. */
821 mtail
= &me
->me_next
;
826 #endif /* MOUNTED_GETFSSTAT */
828 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
831 char *table
= "/etc/mnttab";
834 fp
= fopen (table
, "r");
838 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
840 me
= xmalloc (sizeof *me
);
841 me
->me_devname
= xstrdup (mnt
.mt_dev
);
842 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
843 me
->me_mntroot
= NULL
;
844 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
846 me
->me_type_malloced
= 0;
850 char typebuf
[FSTYPSZ
];
852 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
853 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
855 me
->me_type
= xstrdup (typebuf
);
856 me
->me_type_malloced
= 1;
859 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
860 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
862 /* Add to the linked list. */
864 mtail
= &me
->me_next
;
869 /* The last fread() call must have failed. */
870 int saved_errno
= errno
;
876 if (fclose (fp
) == EOF
)
879 #endif /* MOUNTED_FREAD_FSTYP. */
881 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
883 struct extmnttab mnt
;
884 const char *table
= MNTTAB
;
888 /* No locking is needed, because the contents of /etc/mnttab is generated
892 fp
= fopen (table
, "r");
897 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
899 me
= xmalloc (sizeof *me
);
900 me
->me_devname
= xstrdup (mnt
.mnt_special
);
901 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
902 me
->me_mntroot
= NULL
;
903 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
904 me
->me_type_malloced
= 1;
905 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
906 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
907 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
909 /* Add to the linked list. */
911 mtail
= &me
->me_next
;
914 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
915 /* Here ret = -1 means success, ret >= 0 means failure. */
924 #endif /* MOUNTED_GETEXTMNTENT */
926 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
929 const char *table
= MNTTAB
;
934 # if defined F_RDLCK && defined F_SETLKW
935 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
936 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
937 for this file name, we should use their macro name instead.
938 (Why not just lock MNTTAB directly? We don't know.) */
940 # define MNTTAB_LOCK "/etc/.mnttab.lock"
942 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
946 flock
.l_type
= F_RDLCK
;
947 flock
.l_whence
= SEEK_SET
;
950 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
953 int saved_errno
= errno
;
959 else if (errno
!= ENOENT
)
964 fp
= fopen (table
, "r");
969 while ((ret
= getmntent (fp
, &mnt
)) == 0)
971 me
= xmalloc (sizeof *me
);
972 me
->me_devname
= xstrdup (mnt
.mnt_special
);
973 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
974 me
->me_mntroot
= NULL
;
975 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
976 me
->me_type_malloced
= 1;
977 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
978 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
979 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
981 /* Add to the linked list. */
983 mtail
= &me
->me_next
;
986 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
987 /* Here ret = -1 means success, ret >= 0 means failure. */
990 if (0 <= lockfd
&& close (lockfd
) != 0)
999 #endif /* MOUNTED_GETMNTENT2. */
1001 #ifdef MOUNTED_VMOUNT /* AIX */
1010 /* Ask how many bytes to allocate for the mounted file system info. */
1012 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
1014 entries
= xmalloc (bufsize
);
1016 /* Get the list of mounted file systems. */
1017 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1020 int saved_errno
= errno
;
1022 errno
= saved_errno
;
1026 for (i
= 0, thisent
= entries
;
1028 i
++, thisent
+= vmp
->vmt_length
)
1030 char *options
, *ignore
;
1032 vmp
= (struct vmount
*) thisent
;
1033 me
= xmalloc (sizeof *me
);
1034 if (vmp
->vmt_flags
& MNT_REMOTE
)
1039 /* Prepend the remote dirname. */
1040 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1041 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1042 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1043 strcpy (me
->me_devname
, host
);
1044 strcat (me
->me_devname
, ":");
1045 strcat (me
->me_devname
, dir
);
1050 me
->me_devname
= xstrdup (thisent
+
1051 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1053 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1054 me
->me_mntroot
= NULL
;
1055 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1056 me
->me_type_malloced
= 1;
1057 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1058 ignore
= strstr (options
, "ignore");
1059 me
->me_dummy
= (ignore
1060 && (ignore
== options
|| ignore
[-1] == ',')
1061 && (ignore
[sizeof "ignore" - 1] == ','
1062 || ignore
[sizeof "ignore" - 1] == '\0'));
1063 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1065 /* Add to the linked list. */
1067 mtail
= &me
->me_next
;
1071 #endif /* MOUNTED_VMOUNT. */
1073 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1075 DIR *dirp
= opendir ("/dev/fs");
1076 char node
[9 + NAME_MAX
];
1079 goto free_then_fail
;
1084 struct dirent entry
;
1085 struct dirent
*result
;
1087 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1088 marked obsolescent in glibc. Use readdir instead. */
1089 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1092 strcpy (node
, "/dev/fs/");
1093 strcat (node
, entry
.d_name
);
1095 if (statvfs (node
, &dev
) == 0)
1097 me
= xmalloc (sizeof *me
);
1098 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1099 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1100 me
->me_mntroot
= NULL
;
1101 me
->me_type
= xstrdup (dev
.f_fstypename
);
1102 me
->me_type_malloced
= 1;
1103 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1104 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1105 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1107 /* Add to the linked list. */
1109 mtail
= &me
->me_next
;
1114 #endif /* MOUNTED_INTERIX_STATVFS */
1120 free_then_fail
: _GL_UNUSED_LABEL
1122 int saved_errno
= errno
;
1127 me
= mount_list
->me_next
;
1128 free_mount_entry (mount_list
);
1132 errno
= saved_errno
;
1137 /* Free a mount entry as returned from read_file_system_list (). */
1139 void free_mount_entry (struct mount_entry
*me
)
1141 free (me
->me_devname
);
1142 free (me
->me_mountdir
);
1143 free (me
->me_mntroot
);
1144 if (me
->me_type_malloced
)