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 any other of the listed types
228 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs).
229 "VM" file systems like prl_fs or vboxsf are not considered remote here. */
230 # define ME_REMOTE(Fs_name, Fs_type) \
231 (strchr (Fs_name, ':') != NULL \
232 || ((Fs_name)[0] == '/' \
233 && (Fs_name)[1] == '/' \
234 && (strcmp (Fs_type, "smbfs") == 0 \
235 || strcmp (Fs_type, "smb3") == 0 \
236 || strcmp (Fs_type, "cifs") == 0)) \
237 || strcmp (Fs_type, "acfs") == 0 \
238 || strcmp (Fs_type, "afs") == 0 \
239 || strcmp (Fs_type, "coda") == 0 \
240 || strcmp (Fs_type, "auristorfs") == 0 \
241 || strcmp (Fs_type, "fhgfs") == 0 \
242 || strcmp (Fs_type, "gpfs") == 0 \
243 || strcmp (Fs_type, "ibrix") == 0 \
244 || strcmp (Fs_type, "ocfs2") == 0 \
245 || strcmp (Fs_type, "vxfs") == 0 \
246 || strcmp ("-hosts", Fs_name) == 0)
249 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
251 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
253 fstype_to_string (short int t
)
348 fsp_to_string (const struct statfs
*fsp
)
350 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
351 return (char *) (fsp
->f_fstypename
);
353 return fstype_to_string (fsp
->f_type
);
357 #endif /* MOUNTED_GETMNTINFO */
359 #ifdef MOUNTED_VMOUNT /* AIX */
361 fstype_to_string (int t
)
365 e
= getvfsbytype (t
);
366 if (!e
|| !e
->vfsent_name
)
369 return e
->vfsent_name
;
371 #endif /* MOUNTED_VMOUNT */
374 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
376 /* Return the device number from MOUNT_OPTIONS, if possible.
377 Otherwise return (dev_t) -1. */
379 dev_from_mount_options (char const *mount_options
)
381 /* GNU/Linux allows file system implementations to define their own
382 meaning for "dev=" mount options, so don't trust the meaning
386 static char const dev_pattern
[] = ",dev=";
387 char const *devopt
= strstr (mount_options
, dev_pattern
);
391 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
393 unsigned long int dev
;
395 dev
= strtoul (optval
, &optvalend
, 16);
396 if (optval
!= optvalend
397 && (*optvalend
== '\0' || *optvalend
== ',')
398 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
399 && dev
== (dev_t
) dev
)
404 (void) mount_options
;
410 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
412 /* Unescape the paths in mount tables.
413 STR is updated in place. */
416 unescape_tab (char *str
)
419 size_t len
= strlen (str
) + 1;
420 for (i
= 0; i
< len
; i
++)
422 if (str
[i
] == '\\' && (i
+ 4 < len
)
423 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
424 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
425 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
427 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
428 (str
[i
+ 2] - '0') * 8 +
437 /* Find the next space in STR, terminate the string there in place,
438 and return that position. Otherwise return NULL. */
441 terminate_at_blank (char *str
)
443 char *s
= strchr (str
, ' ');
450 /* Return a list of the currently mounted file systems, or NULL on error.
451 Add each entry to the tail of the list so that they stay in order.
452 If NEED_FS_TYPE is true, ensure that the file system type fields in
453 the returned list are valid. Otherwise, they might not be. */
456 read_file_system_list (bool need_fs_type
)
458 struct mount_entry
*mount_list
;
459 struct mount_entry
*me
;
460 struct mount_entry
**mtail
= &mount_list
;
463 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
464 also (obsolete) 4.3BSD, SunOS */
468 # if defined __linux__ || defined __ANDROID__
469 /* Try parsing mountinfo first, as that make device IDs available.
470 Note we could use libmount routines to simplify this parsing a little
471 (and that code is in previous versions of this function), however
472 libmount depends on libselinux which pulls in many dependencies. */
473 char const *mountinfo
= "/proc/self/mountinfo";
474 fp
= fopen (mountinfo
, "re");
480 while (getline (&line
, &buf_size
, fp
) != -1)
482 unsigned int devmaj
, devmin
;
485 rc
= sscanf(line
, "%*u " /* id - discarded */
486 "%*u " /* parent - discarded */
487 "%u:%u " /* dev major:minor */
488 "%n", /* mountroot (start) */
492 if (rc
!= 2 && rc
!= 3) /* 3 if %n included in count. */
495 /* find end of MNTROOT. */
496 char *mntroot
= line
+ mntroot_s
;
497 char *blank
= terminate_at_blank (mntroot
);
501 /* find end of TARGET. */
502 char *target
= blank
+ 1;
503 blank
= terminate_at_blank (target
);
507 /* skip optional fields, terminated by " - " */
508 char *dash
= strstr (blank
+ 1, " - ");
512 /* advance past the " - " separator. */
513 char *fstype
= dash
+ 3;
514 blank
= terminate_at_blank (fstype
);
518 /* find end of SOURCE. */
519 char *source
= blank
+ 1;
520 if (! terminate_at_blank (source
))
523 /* manipulate the sub-strings in place. */
524 unescape_tab (source
);
525 unescape_tab (target
);
526 unescape_tab (mntroot
);
527 unescape_tab (fstype
);
529 me
= xmalloc (sizeof *me
);
531 me
->me_devname
= xstrdup (source
);
532 me
->me_mountdir
= xstrdup (target
);
533 me
->me_mntroot
= xstrdup (mntroot
);
534 me
->me_type
= xstrdup (fstype
);
535 me
->me_type_malloced
= 1;
536 me
->me_dev
= makedev (devmaj
, devmin
);
537 /* we pass "false" for the "Bind" option as that's only
538 significant when the Fs_type is "none" which will not be
539 the case when parsing "/proc/self/mountinfo", and only
540 applies for static /etc/mtab files. */
541 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
542 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
544 /* Add to the linked list. */
546 mtail
= &me
->me_next
;
553 int saved_errno
= errno
;
559 if (fclose (fp
) == EOF
)
562 else /* fallback to /proc/self/mounts (/etc/mtab). */
563 # endif /* __linux __ || __ANDROID__ */
566 char const *table
= MOUNTED
;
568 fp
= setmntent (table
, "r");
572 while ((mnt
= getmntent (fp
)))
574 bool bind
= hasmntopt (mnt
, "bind");
576 me
= xmalloc (sizeof *me
);
577 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
578 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
579 me
->me_mntroot
= NULL
;
580 me
->me_type
= xstrdup (mnt
->mnt_type
);
581 me
->me_type_malloced
= 1;
582 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
583 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
584 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
586 /* Add to the linked list. */
588 mtail
= &me
->me_next
;
591 if (endmntent (fp
) == 0)
595 #endif /* MOUNTED_GETMNTENT1. */
597 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
602 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
605 for (; entries
-- > 0; fsp
++)
607 char *fs_type
= fsp_to_string (fsp
);
609 me
= xmalloc (sizeof *me
);
610 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
611 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
612 me
->me_mntroot
= NULL
;
613 me
->me_type
= fs_type
;
614 me
->me_type_malloced
= 0;
615 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
616 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
617 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
619 /* Add to the linked list. */
621 mtail
= &me
->me_next
;
624 #endif /* MOUNTED_GETMNTINFO */
626 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
631 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
634 for (; entries
-- > 0; fsp
++)
636 me
= xmalloc (sizeof *me
);
637 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
638 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
639 me
->me_mntroot
= NULL
;
640 me
->me_type
= xstrdup (fsp
->f_fstypename
);
641 me
->me_type_malloced
= 1;
642 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
643 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
644 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
646 /* Add to the linked list. */
648 mtail
= &me
->me_next
;
651 #endif /* MOUNTED_GETMNTINFO2 */
653 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
655 /* The next_dev() and fs_stat_dev() system calls give the list of
656 all file systems, including the information returned by statvfs()
657 (fs type, total blocks, free blocks etc.), but without the mount
658 point. But on BeOS all file systems except / are mounted in the
659 rootfs, directly under /.
660 The directory name of the mount point is often, but not always,
661 identical to the volume name of the device.
662 We therefore get the list of subdirectories of /, and the list
663 of all file systems, and match the two lists. */
671 struct rootdir_entry
*next
;
673 struct rootdir_entry
*rootdir_list
;
674 struct rootdir_entry
**rootdir_tail
;
679 /* All volumes are mounted in the rootfs, directly under /. */
681 rootdir_tail
= &rootdir_list
;
682 dirp
= opendir ("/");
687 while ((d
= readdir (dirp
)) != NULL
)
692 if (strcmp (d
->d_name
, "..") == 0)
695 if (strcmp (d
->d_name
, ".") == 0)
696 name
= xstrdup ("/");
699 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
701 strcpy (name
+ 1, d
->d_name
);
704 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
706 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
708 re
->dev
= statbuf
.st_dev
;
709 re
->ino
= statbuf
.st_ino
;
711 /* Add to the linked list. */
713 rootdir_tail
= &re
->next
;
720 *rootdir_tail
= NULL
;
722 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
723 if (fs_stat_dev (dev
, &fi
) >= 0)
725 /* Note: fi.dev == dev. */
726 struct rootdir_entry
*re
;
728 for (re
= rootdir_list
; re
; re
= re
->next
)
729 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
732 me
= xmalloc (sizeof *me
);
733 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
734 ? fi
.device_name
: fi
.fsh_name
);
735 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
736 me
->me_mntroot
= NULL
;
737 me
->me_type
= xstrdup (fi
.fsh_name
);
738 me
->me_type_malloced
= 1;
741 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
743 /* Add to the linked list. */
745 mtail
= &me
->me_next
;
749 while (rootdir_list
!= NULL
)
751 struct rootdir_entry
*re
= rootdir_list
;
752 rootdir_list
= re
->next
;
757 #endif /* MOUNTED_FS_STAT_DEV */
759 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
763 struct statfs
*stats
;
765 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
768 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
771 bufsize
= (1 + numsys
) * sizeof *stats
;
772 stats
= xmalloc (bufsize
);
773 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
781 for (counter
= 0; counter
< numsys
; counter
++)
783 me
= xmalloc (sizeof *me
);
784 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
785 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
786 me
->me_mntroot
= NULL
;
787 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
788 me
->me_type_malloced
= 1;
789 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
790 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
791 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
793 /* Add to the linked list. */
795 mtail
= &me
->me_next
;
800 #endif /* MOUNTED_GETFSSTAT */
802 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
805 char *table
= "/etc/mnttab";
808 fp
= fopen (table
, "re");
812 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
814 me
= xmalloc (sizeof *me
);
815 me
->me_devname
= xstrdup (mnt
.mt_dev
);
816 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
817 me
->me_mntroot
= NULL
;
818 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
820 me
->me_type_malloced
= 0;
824 char typebuf
[FSTYPSZ
];
826 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
827 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
829 me
->me_type
= xstrdup (typebuf
);
830 me
->me_type_malloced
= 1;
833 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
834 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
836 /* Add to the linked list. */
838 mtail
= &me
->me_next
;
843 /* The last fread() call must have failed. */
844 int saved_errno
= errno
;
850 if (fclose (fp
) == EOF
)
853 #endif /* MOUNTED_FREAD_FSTYP. */
855 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
857 struct extmnttab mnt
;
858 const char *table
= MNTTAB
;
862 /* No locking is needed, because the contents of /etc/mnttab is generated
866 fp
= fopen (table
, "re");
871 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
873 me
= xmalloc (sizeof *me
);
874 me
->me_devname
= xstrdup (mnt
.mnt_special
);
875 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
876 me
->me_mntroot
= NULL
;
877 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
878 me
->me_type_malloced
= 1;
879 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
880 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
881 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
883 /* Add to the linked list. */
885 mtail
= &me
->me_next
;
888 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
889 /* Here ret = -1 means success, ret >= 0 means failure. */
898 #endif /* MOUNTED_GETEXTMNTENT */
900 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
903 const char *table
= MNTTAB
;
908 # if defined F_RDLCK && defined F_SETLKW
909 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
910 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
911 for this file name, we should use their macro name instead.
912 (Why not just lock MNTTAB directly? We don't know.) */
914 # define MNTTAB_LOCK "/etc/.mnttab.lock"
916 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
| O_CLOEXEC
);
920 flock
.l_type
= F_RDLCK
;
921 flock
.l_whence
= SEEK_SET
;
924 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
927 int saved_errno
= errno
;
933 else if (errno
!= ENOENT
)
938 fp
= fopen (table
, "re");
943 while ((ret
= getmntent (fp
, &mnt
)) == 0)
945 me
= xmalloc (sizeof *me
);
946 me
->me_devname
= xstrdup (mnt
.mnt_special
);
947 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
948 me
->me_mntroot
= NULL
;
949 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
950 me
->me_type_malloced
= 1;
951 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
952 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
953 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
955 /* Add to the linked list. */
957 mtail
= &me
->me_next
;
960 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
961 /* Here ret = -1 means success, ret >= 0 means failure. */
964 if (0 <= lockfd
&& close (lockfd
) != 0)
973 #endif /* MOUNTED_GETMNTENT2. */
975 #ifdef MOUNTED_VMOUNT /* AIX */
984 /* Ask how many bytes to allocate for the mounted file system info. */
986 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
988 entries
= xmalloc (bufsize
);
990 /* Get the list of mounted file systems. */
991 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
994 int saved_errno
= errno
;
1000 for (i
= 0, thisent
= entries
;
1002 i
++, thisent
+= vmp
->vmt_length
)
1004 char *options
, *ignore
;
1006 vmp
= (struct vmount
*) thisent
;
1007 me
= xmalloc (sizeof *me
);
1008 if (vmp
->vmt_flags
& MNT_REMOTE
)
1013 /* Prepend the remote dirname. */
1014 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1015 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1016 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1017 strcpy (me
->me_devname
, host
);
1018 strcat (me
->me_devname
, ":");
1019 strcat (me
->me_devname
, dir
);
1024 me
->me_devname
= xstrdup (thisent
+
1025 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1027 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1028 me
->me_mntroot
= NULL
;
1029 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1030 me
->me_type_malloced
= 1;
1031 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1032 ignore
= strstr (options
, "ignore");
1033 me
->me_dummy
= (ignore
1034 && (ignore
== options
|| ignore
[-1] == ',')
1035 && (ignore
[sizeof "ignore" - 1] == ','
1036 || ignore
[sizeof "ignore" - 1] == '\0'));
1037 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1039 /* Add to the linked list. */
1041 mtail
= &me
->me_next
;
1045 #endif /* MOUNTED_VMOUNT. */
1047 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1049 DIR *dirp
= opendir ("/dev/fs");
1050 char node
[9 + NAME_MAX
];
1053 goto free_then_fail
;
1058 struct dirent entry
;
1059 struct dirent
*result
;
1061 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1062 marked obsolescent in glibc. Use readdir instead. */
1063 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1066 strcpy (node
, "/dev/fs/");
1067 strcat (node
, entry
.d_name
);
1069 if (statvfs (node
, &dev
) == 0)
1071 me
= xmalloc (sizeof *me
);
1072 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1073 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1074 me
->me_mntroot
= NULL
;
1075 me
->me_type
= xstrdup (dev
.f_fstypename
);
1076 me
->me_type_malloced
= 1;
1077 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1078 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1079 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1081 /* Add to the linked list. */
1083 mtail
= &me
->me_next
;
1088 #endif /* MOUNTED_INTERIX_STATVFS */
1094 free_then_fail
: _GL_UNUSED_LABEL
1096 int saved_errno
= errno
;
1101 me
= mount_list
->me_next
;
1102 free_mount_entry (mount_list
);
1106 errno
= saved_errno
;
1111 /* Free a mount entry as returned from read_file_system_list (). */
1113 void free_mount_entry (struct mount_entry
*me
)
1115 free (me
->me_devname
);
1116 free (me
->me_mountdir
);
1117 free (me
->me_mntroot
);
1118 if (me
->me_type_malloced
)