1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2024 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
152 /* Each of the FILE streams in this file is only used in a single thread. */
153 #include "unlocked-io.h"
155 /* The results of opendir() in this file are not used with dirfd and fchdir,
156 therefore save some unnecessary work in fchdir.c. */
157 #ifdef GNULIB_defined_DIR
163 # ifdef GNULIB_defined_opendir
166 # ifdef GNULIB_defined_closedir
171 #define ME_DUMMY_0(Fs_name, Fs_type) \
172 (strcmp (Fs_type, "autofs") == 0 \
173 || strcmp (Fs_type, "proc") == 0 \
174 || strcmp (Fs_type, "subfs") == 0 \
175 /* for Linux 2.6/3.x */ \
176 || strcmp (Fs_type, "debugfs") == 0 \
177 || strcmp (Fs_type, "devpts") == 0 \
178 || strcmp (Fs_type, "fusectl") == 0 \
179 || strcmp (Fs_type, "fuse.portal") == 0 \
180 || strcmp (Fs_type, "mqueue") == 0 \
181 || strcmp (Fs_type, "rpc_pipefs") == 0 \
182 || strcmp (Fs_type, "sysfs") == 0 \
183 /* FreeBSD, Linux 2.4 */ \
184 || strcmp (Fs_type, "devfs") == 0 \
185 /* for NetBSD 3.0 */ \
186 || strcmp (Fs_type, "kernfs") == 0 \
188 || strcmp (Fs_type, "ignore") == 0)
190 /* Historically, we have marked as "dummy" any file system of type "none",
191 but now that programs like du need to know about bind-mounted directories,
192 we grant an exception to any with "bind" in its list of mount options.
193 I.e., those are *not* dummy entries. */
194 #ifdef MOUNTED_GETMNTENT1
195 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
196 (ME_DUMMY_0 (Fs_name, Fs_type) \
197 || (strcmp (Fs_type, "none") == 0 && !Bind))
199 # define ME_DUMMY(Fs_name, Fs_type) \
200 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
204 # include <windows.h>
205 /* Don't assume that UNICODE is not defined. */
207 # define GetDriveType GetDriveTypeA
208 # define ME_REMOTE me_remote
209 /* All cygwin mount points include ':' or start with '//'; so it
210 requires a native Windows call to determine remote disks. */
212 me_remote (char const *fs_name
, _GL_UNUSED
char const *fs_type
)
214 if (fs_name
[0] && fs_name
[1] == ':')
217 sprintf (drive
, "%c:\\", fs_name
[0]);
218 switch (GetDriveType (drive
))
220 case DRIVE_REMOVABLE
:
232 /* A file system is "remote" if its Fs_name contains a ':'
233 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
234 or if it is of any other of the listed types
235 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs).
236 "VM" file systems like prl_fs or vboxsf are not considered remote here. */
237 # define ME_REMOTE(Fs_name, Fs_type) \
238 (strchr (Fs_name, ':') != NULL \
239 || ((Fs_name)[0] == '/' \
240 && (Fs_name)[1] == '/' \
241 && (strcmp (Fs_type, "smbfs") == 0 \
242 || strcmp (Fs_type, "smb3") == 0 \
243 || strcmp (Fs_type, "cifs") == 0)) \
244 || strcmp (Fs_type, "acfs") == 0 \
245 || strcmp (Fs_type, "afs") == 0 \
246 || strcmp (Fs_type, "coda") == 0 \
247 || strcmp (Fs_type, "auristorfs") == 0 \
248 || strcmp (Fs_type, "fhgfs") == 0 \
249 || strcmp (Fs_type, "gpfs") == 0 \
250 || strcmp (Fs_type, "ibrix") == 0 \
251 || strcmp (Fs_type, "ocfs2") == 0 \
252 || strcmp (Fs_type, "vxfs") == 0 \
253 || strcmp ("-hosts", Fs_name) == 0)
256 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
258 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
260 fstype_to_string (short int t
)
355 fsp_to_string (const struct statfs
*fsp
)
357 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
358 return (char *) (fsp
->f_fstypename
);
360 return fstype_to_string (fsp
->f_type
);
364 #endif /* MOUNTED_GETMNTINFO */
366 #ifdef MOUNTED_VMOUNT /* AIX */
368 fstype_to_string (int t
)
372 e
= getvfsbytype (t
);
373 if (!e
|| !e
->vfsent_name
)
376 return e
->vfsent_name
;
378 #endif /* MOUNTED_VMOUNT */
381 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
383 /* Return the device number from MOUNT_OPTIONS, if possible.
384 Otherwise return (dev_t) -1. */
386 dev_from_mount_options (char const *mount_options
)
388 /* GNU/Linux allows file system implementations to define their own
389 meaning for "dev=" mount options, so don't trust the meaning
393 static char const dev_pattern
[] = ",dev=";
394 char const *devopt
= strstr (mount_options
, dev_pattern
);
398 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
400 unsigned long int dev
;
402 dev
= strtoul (optval
, &optvalend
, 16);
403 if (optval
!= optvalend
404 && (*optvalend
== '\0' || *optvalend
== ',')
405 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
406 && dev
== (dev_t
) dev
)
411 (void) mount_options
;
417 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
419 /* Unescape the paths in mount tables.
420 STR is updated in place. */
423 unescape_tab (char *str
)
426 size_t len
= strlen (str
) + 1;
427 for (i
= 0; i
< len
; i
++)
429 if (str
[i
] == '\\' && (i
+ 4 < len
)
430 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
431 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
432 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
434 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
435 (str
[i
+ 2] - '0') * 8 +
444 /* Find the next space in STR, terminate the string there in place,
445 and return that position. Otherwise return NULL. */
448 terminate_at_blank (char *str
)
450 char *s
= strchr (str
, ' ');
457 /* Return a list of the currently mounted file systems, or NULL on error.
458 Add each entry to the tail of the list so that they stay in order.
459 If NEED_FS_TYPE is true, ensure that the file system type fields in
460 the returned list are valid. Otherwise, they might not be. */
463 read_file_system_list (bool need_fs_type
)
465 struct mount_entry
*mount_list
;
466 struct mount_entry
*me
;
467 struct mount_entry
**mtail
= &mount_list
;
470 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
471 also (obsolete) 4.3BSD, SunOS */
475 # if defined __linux__ || defined __ANDROID__
476 /* Try parsing mountinfo first, as that make device IDs available.
477 Note we could use libmount routines to simplify this parsing a little
478 (and that code is in previous versions of this function), however
479 libmount depends on libselinux which pulls in many dependencies. */
480 char const *mountinfo
= "/proc/self/mountinfo";
481 fp
= fopen (mountinfo
, "re");
487 while (getline (&line
, &buf_size
, fp
) != -1)
489 unsigned int devmaj
, devmin
;
492 rc
= sscanf(line
, "%*u " /* id - discarded */
493 "%*u " /* parent - discarded */
494 "%u:%u " /* dev major:minor */
495 "%n", /* mountroot (start) */
499 if (rc
!= 2 && rc
!= 3) /* 3 if %n included in count. */
502 /* find end of MNTROOT. */
503 char *mntroot
= line
+ mntroot_s
;
504 char *blank
= terminate_at_blank (mntroot
);
508 /* find end of TARGET. */
509 char *target
= blank
+ 1;
510 blank
= terminate_at_blank (target
);
514 /* skip optional fields, terminated by " - " */
515 char *dash
= strstr (blank
+ 1, " - ");
519 /* advance past the " - " separator. */
520 char *fstype
= dash
+ 3;
521 blank
= terminate_at_blank (fstype
);
525 /* find end of SOURCE. */
526 char *source
= blank
+ 1;
527 if (! terminate_at_blank (source
))
530 /* manipulate the sub-strings in place. */
531 unescape_tab (source
);
532 unescape_tab (target
);
533 unescape_tab (mntroot
);
534 unescape_tab (fstype
);
536 me
= xmalloc (sizeof *me
);
538 me
->me_devname
= xstrdup (source
);
539 me
->me_mountdir
= xstrdup (target
);
540 me
->me_mntroot
= xstrdup (mntroot
);
541 me
->me_type
= xstrdup (fstype
);
542 me
->me_type_malloced
= 1;
543 me
->me_dev
= makedev (devmaj
, devmin
);
544 /* we pass "false" for the "Bind" option as that's only
545 significant when the Fs_type is "none" which will not be
546 the case when parsing "/proc/self/mountinfo", and only
547 applies for static /etc/mtab files. */
548 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
549 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
551 /* Add to the linked list. */
553 mtail
= &me
->me_next
;
560 int saved_errno
= errno
;
566 if (fclose (fp
) == EOF
)
569 else /* fallback to /proc/self/mounts (/etc/mtab). */
570 # endif /* __linux __ || __ANDROID__ */
573 char const *table
= MOUNTED
;
575 fp
= setmntent (table
, "r");
579 while ((mnt
= getmntent (fp
)))
581 bool bind
= hasmntopt (mnt
, "bind");
583 me
= xmalloc (sizeof *me
);
584 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
585 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
586 me
->me_mntroot
= NULL
;
587 me
->me_type
= xstrdup (mnt
->mnt_type
);
588 me
->me_type_malloced
= 1;
589 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
590 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
591 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
593 /* Add to the linked list. */
595 mtail
= &me
->me_next
;
598 if (endmntent (fp
) == 0)
602 #endif /* MOUNTED_GETMNTENT1. */
604 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
609 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
612 for (; entries
-- > 0; fsp
++)
614 char *fs_type
= fsp_to_string (fsp
);
616 me
= xmalloc (sizeof *me
);
617 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
618 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
619 me
->me_mntroot
= NULL
;
620 me
->me_type
= fs_type
;
621 me
->me_type_malloced
= 0;
622 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
623 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
624 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
626 /* Add to the linked list. */
628 mtail
= &me
->me_next
;
631 #endif /* MOUNTED_GETMNTINFO */
633 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
638 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
641 for (; entries
-- > 0; fsp
++)
643 me
= xmalloc (sizeof *me
);
644 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
645 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
646 me
->me_mntroot
= NULL
;
647 me
->me_type
= xstrdup (fsp
->f_fstypename
);
648 me
->me_type_malloced
= 1;
649 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
650 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
651 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
653 /* Add to the linked list. */
655 mtail
= &me
->me_next
;
658 #endif /* MOUNTED_GETMNTINFO2 */
660 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
662 /* The next_dev() and fs_stat_dev() system calls give the list of
663 all file systems, including the information returned by statvfs()
664 (fs type, total blocks, free blocks etc.), but without the mount
665 point. But on BeOS all file systems except / are mounted in the
666 rootfs, directly under /.
667 The directory name of the mount point is often, but not always,
668 identical to the volume name of the device.
669 We therefore get the list of subdirectories of /, and the list
670 of all file systems, and match the two lists. */
678 struct rootdir_entry
*next
;
680 struct rootdir_entry
*rootdir_list
;
681 struct rootdir_entry
**rootdir_tail
;
686 /* All volumes are mounted in the rootfs, directly under /. */
688 rootdir_tail
= &rootdir_list
;
689 dirp
= opendir ("/");
694 while ((d
= readdir (dirp
)) != NULL
)
699 if (strcmp (d
->d_name
, "..") == 0)
702 if (strcmp (d
->d_name
, ".") == 0)
703 name
= xstrdup ("/");
706 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
708 strcpy (name
+ 1, d
->d_name
);
711 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
713 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
715 re
->dev
= statbuf
.st_dev
;
716 re
->ino
= statbuf
.st_ino
;
718 /* Add to the linked list. */
720 rootdir_tail
= &re
->next
;
727 *rootdir_tail
= NULL
;
729 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
730 if (fs_stat_dev (dev
, &fi
) >= 0)
732 /* Note: fi.dev == dev. */
733 struct rootdir_entry
*re
;
735 for (re
= rootdir_list
; re
; re
= re
->next
)
736 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
739 me
= xmalloc (sizeof *me
);
740 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
741 ? fi
.device_name
: fi
.fsh_name
);
742 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
743 me
->me_mntroot
= NULL
;
744 me
->me_type
= xstrdup (fi
.fsh_name
);
745 me
->me_type_malloced
= 1;
748 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
750 /* Add to the linked list. */
752 mtail
= &me
->me_next
;
756 while (rootdir_list
!= NULL
)
758 struct rootdir_entry
*re
= rootdir_list
;
759 rootdir_list
= re
->next
;
764 #endif /* MOUNTED_FS_STAT_DEV */
766 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
770 struct statfs
*stats
;
772 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
775 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
778 bufsize
= (1 + numsys
) * sizeof *stats
;
779 stats
= xmalloc (bufsize
);
780 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
788 for (counter
= 0; counter
< numsys
; counter
++)
790 me
= xmalloc (sizeof *me
);
791 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
792 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
793 me
->me_mntroot
= NULL
;
794 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
795 me
->me_type_malloced
= 1;
796 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
797 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
798 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
800 /* Add to the linked list. */
802 mtail
= &me
->me_next
;
807 #endif /* MOUNTED_GETFSSTAT */
809 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
812 char *table
= "/etc/mnttab";
815 fp
= fopen (table
, "re");
819 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
821 me
= xmalloc (sizeof *me
);
822 me
->me_devname
= xstrdup (mnt
.mt_dev
);
823 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
824 me
->me_mntroot
= NULL
;
825 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
827 me
->me_type_malloced
= 0;
831 char typebuf
[FSTYPSZ
];
833 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
834 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
836 me
->me_type
= xstrdup (typebuf
);
837 me
->me_type_malloced
= 1;
840 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
841 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
843 /* Add to the linked list. */
845 mtail
= &me
->me_next
;
850 /* The last fread() call must have failed. */
851 int saved_errno
= errno
;
857 if (fclose (fp
) == EOF
)
860 #endif /* MOUNTED_FREAD_FSTYP. */
862 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
864 struct extmnttab mnt
;
865 const char *table
= MNTTAB
;
869 /* No locking is needed, because the contents of /etc/mnttab is generated
873 fp
= fopen (table
, "re");
878 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
880 me
= xmalloc (sizeof *me
);
881 me
->me_devname
= xstrdup (mnt
.mnt_special
);
882 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
883 me
->me_mntroot
= NULL
;
884 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
885 me
->me_type_malloced
= 1;
886 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
887 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
888 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
890 /* Add to the linked list. */
892 mtail
= &me
->me_next
;
895 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
896 /* Here ret = -1 means success, ret >= 0 means failure. */
905 #endif /* MOUNTED_GETEXTMNTENT */
907 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
910 const char *table
= MNTTAB
;
915 # if defined F_RDLCK && defined F_SETLKW
916 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
917 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
918 for this file name, we should use their macro name instead.
919 (Why not just lock MNTTAB directly? We don't know.) */
921 # define MNTTAB_LOCK "/etc/.mnttab.lock"
923 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
| O_CLOEXEC
);
927 flock
.l_type
= F_RDLCK
;
928 flock
.l_whence
= SEEK_SET
;
931 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
934 int saved_errno
= errno
;
940 else if (errno
!= ENOENT
)
945 fp
= fopen (table
, "re");
950 while ((ret
= getmntent (fp
, &mnt
)) == 0)
952 me
= xmalloc (sizeof *me
);
953 me
->me_devname
= xstrdup (mnt
.mnt_special
);
954 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
955 me
->me_mntroot
= NULL
;
956 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
957 me
->me_type_malloced
= 1;
958 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
959 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
960 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
962 /* Add to the linked list. */
964 mtail
= &me
->me_next
;
967 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
968 /* Here ret = -1 means success, ret >= 0 means failure. */
971 if (0 <= lockfd
&& close (lockfd
) != 0)
980 #endif /* MOUNTED_GETMNTENT2. */
982 #ifdef MOUNTED_VMOUNT /* AIX */
991 /* Ask how many bytes to allocate for the mounted file system info. */
993 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
995 entries
= xmalloc (bufsize
);
997 /* Get the list of mounted file systems. */
998 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1005 for (i
= 0, thisent
= entries
;
1007 i
++, thisent
+= vmp
->vmt_length
)
1009 char *options
, *ignore
;
1011 vmp
= (struct vmount
*) thisent
;
1012 me
= xmalloc (sizeof *me
);
1013 if (vmp
->vmt_flags
& MNT_REMOTE
)
1018 /* Prepend the remote dirname. */
1019 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1020 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1021 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1022 strcpy (me
->me_devname
, host
);
1023 strcat (me
->me_devname
, ":");
1024 strcat (me
->me_devname
, dir
);
1029 me
->me_devname
= xstrdup (thisent
+
1030 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1032 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1033 me
->me_mntroot
= NULL
;
1034 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1035 me
->me_type_malloced
= 1;
1036 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1037 ignore
= strstr (options
, "ignore");
1038 me
->me_dummy
= (ignore
1039 && (ignore
== options
|| ignore
[-1] == ',')
1040 && (ignore
[sizeof "ignore" - 1] == ','
1041 || ignore
[sizeof "ignore" - 1] == '\0'));
1042 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1044 /* Add to the linked list. */
1046 mtail
= &me
->me_next
;
1050 #endif /* MOUNTED_VMOUNT. */
1052 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1054 DIR *dirp
= opendir ("/dev/fs");
1055 char node
[9 + NAME_MAX
];
1058 goto free_then_fail
;
1063 struct dirent entry
;
1064 struct dirent
*result
;
1066 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1067 marked obsolescent in glibc. Use readdir instead. */
1068 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1071 strcpy (node
, "/dev/fs/");
1072 strcat (node
, entry
.d_name
);
1074 if (statvfs (node
, &dev
) == 0)
1076 me
= xmalloc (sizeof *me
);
1077 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1078 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1079 me
->me_mntroot
= NULL
;
1080 me
->me_type
= xstrdup (dev
.f_fstypename
);
1081 me
->me_type_malloced
= 1;
1082 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1083 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1084 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1086 /* Add to the linked list. */
1088 mtail
= &me
->me_next
;
1093 #endif /* MOUNTED_INTERIX_STATVFS */
1099 free_then_fail
: _GL_UNUSED_LABEL
;
1101 int saved_errno
= errno
;
1106 me
= mount_list
->me_next
;
1107 free_mount_entry (mount_list
);
1111 errno
= saved_errno
;
1116 /* Free a mount entry as returned from read_file_system_list (). */
1119 free_mount_entry (struct mount_entry
*me
)
1121 free (me
->me_devname
);
1122 free (me
->me_mountdir
);
1123 free (me
->me_mntroot
);
1124 if (me
->me_type_malloced
)