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, Dynix */
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
76 # if defined MNTTABNAME /* Dynix. */
77 # define MOUNTED MNTTABNAME
82 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
83 # include <sys/mount.h>
86 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
87 # include <sys/statvfs.h>
90 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
91 # include <sys/mount.h>
92 # include <sys/fs_types.h>
95 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
100 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
102 # include <sys/fstyp.h>
103 # include <sys/statfs.h>
106 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
110 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
111 # include <sys/mnttab.h>
114 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
115 # include <sys/mnttab.h>
118 #ifdef MOUNTED_VMOUNT /* AIX */
120 # include <sys/vfs.h>
123 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
124 # include <sys/statvfs.h>
129 /* So special that it's not worth putting this in autoconf. */
130 # undef MOUNTED_FREAD_FSTYP
131 # define MOUNTED_GETMNTTBL
134 #if HAVE_SYS_MNTENT_H
135 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
136 # include <sys/mntent.h>
139 #ifndef HAVE_HASMNTOPT
140 # define hasmntopt(mnt, opt) ((char *) 0)
145 # if defined __sun && defined __SVR4
146 /* Solaris defines hasmntopt(struct mnttab *, char *)
147 while it is otherwise hasmntopt(struct mnttab *, const char *). */
148 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
150 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
153 # define MNT_IGNORE(M) 0
157 # include "unlocked-io.h"
160 /* The results of opendir() in this file are not used with dirfd and fchdir,
161 therefore save some unnecessary work in fchdir.c. */
162 #ifdef GNULIB_defined_opendir
165 #ifdef GNULIB_defined_closedir
169 #define ME_DUMMY_0(Fs_name, Fs_type) \
170 (strcmp (Fs_type, "autofs") == 0 \
171 || strcmp (Fs_type, "proc") == 0 \
172 || strcmp (Fs_type, "subfs") == 0 \
173 /* for Linux 2.6/3.x */ \
174 || strcmp (Fs_type, "debugfs") == 0 \
175 || strcmp (Fs_type, "devpts") == 0 \
176 || strcmp (Fs_type, "fusectl") == 0 \
177 || strcmp (Fs_type, "mqueue") == 0 \
178 || strcmp (Fs_type, "rpc_pipefs") == 0 \
179 || strcmp (Fs_type, "sysfs") == 0 \
180 /* FreeBSD, Linux 2.4 */ \
181 || strcmp (Fs_type, "devfs") == 0 \
182 /* for NetBSD 3.0 */ \
183 || strcmp (Fs_type, "kernfs") == 0 \
185 || strcmp (Fs_type, "ignore") == 0)
187 /* Historically, we have marked as "dummy" any file system of type "none",
188 but now that programs like du need to know about bind-mounted directories,
189 we grant an exception to any with "bind" in its list of mount options.
190 I.e., those are *not* dummy entries. */
191 #ifdef MOUNTED_GETMNTENT1
192 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
193 (ME_DUMMY_0 (Fs_name, Fs_type) \
194 || (strcmp (Fs_type, "none") == 0 && !Bind))
196 # define ME_DUMMY(Fs_name, Fs_type) \
197 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
201 # include <windows.h>
202 # define ME_REMOTE me_remote
203 /* All cygwin mount points include ':' or start with '//'; so it
204 requires a native Windows call to determine remote disks. */
206 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
208 if (fs_name
[0] && fs_name
[1] == ':')
211 sprintf (drive
, "%c:\\", fs_name
[0]);
212 switch (GetDriveType (drive
))
214 case DRIVE_REMOVABLE
:
226 /* A file system is "remote" if its Fs_name contains a ':'
227 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
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, "cifs") == 0)) \
235 || (strcmp("-hosts", Fs_name) == 0))
238 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
240 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
242 fstype_to_string (short int t
)
337 fsp_to_string (const struct statfs
*fsp
)
339 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
340 return (char *) (fsp
->f_fstypename
);
342 return fstype_to_string (fsp
->f_type
);
346 #endif /* MOUNTED_GETMNTINFO */
348 #ifdef MOUNTED_VMOUNT /* AIX */
350 fstype_to_string (int t
)
354 e
= getvfsbytype (t
);
355 if (!e
|| !e
->vfsent_name
)
358 return e
->vfsent_name
;
360 #endif /* MOUNTED_VMOUNT */
363 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
365 /* Return the device number from MOUNT_OPTIONS, if possible.
366 Otherwise return (dev_t) -1. */
368 dev_from_mount_options (char const *mount_options
)
370 /* GNU/Linux allows file system implementations to define their own
371 meaning for "dev=" mount options, so don't trust the meaning
375 static char const dev_pattern
[] = ",dev=";
376 char const *devopt
= strstr (mount_options
, dev_pattern
);
380 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
382 unsigned long int dev
;
384 dev
= strtoul (optval
, &optvalend
, 16);
385 if (optval
!= optvalend
386 && (*optvalend
== '\0' || *optvalend
== ',')
387 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
388 && dev
== (dev_t
) dev
)
393 (void) mount_options
;
399 #if defined MOUNTED_GETMNTENT1 && defined __linux__ /* GNU/Linux, Android */
401 /* Unescape the paths in mount tables.
402 STR is updated in place. */
405 unescape_tab (char *str
)
408 size_t len
= strlen (str
) + 1;
409 for (i
= 0; i
< len
; i
++)
411 if (str
[i
] == '\\' && (i
+ 4 < len
)
412 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
413 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
414 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
416 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
417 (str
[i
+ 2] - '0') * 8 +
427 /* Return a list of the currently mounted file systems, or NULL on error.
428 Add each entry to the tail of the list so that they stay in order.
429 If NEED_FS_TYPE is true, ensure that the file system type fields in
430 the returned list are valid. Otherwise, they might not be. */
433 read_file_system_list (bool need_fs_type
)
435 struct mount_entry
*mount_list
;
436 struct mount_entry
*me
;
437 struct mount_entry
**mtail
= &mount_list
;
440 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
442 struct tabmntent
*mntlist
, *p
;
445 /* the third and fourth arguments could be used to filter mounts,
446 but Crays doesn't seem to have any mounts that we want to
447 remove. Specifically, automount create normal NFS mounts.
450 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
452 for (p
= mntlist
; p
; p
= p
->next
)
455 me
= xmalloc (sizeof *me
);
456 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
457 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
458 me
->me_mntroot
= NULL
;
459 me
->me_type
= xstrdup (mnt
->mnt_type
);
460 me
->me_type_malloced
= 1;
461 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
462 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
465 mtail
= &me
->me_next
;
467 freemntlist (mntlist
);
471 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
472 also (obsolete) 4.3BSD, SunOS, Dynix */
477 /* Try parsing mountinfo first, as that make device IDs available.
478 Note we could use libmount routines to simplify this parsing a little
479 (and that code is in previous versions of this function), however
480 libmount depends on libselinux which pulls in many dependencies. */
481 char const *mountinfo
= "/proc/self/mountinfo";
482 fp
= fopen (mountinfo
, "r");
488 while (getline (&line
, &buf_size
, fp
) != -1)
490 unsigned int devmaj
, devmin
;
491 int target_s
, target_e
, type_s
, type_e
;
492 int source_s
, source_e
, mntroot_s
, mntroot_e
;
497 rc
= sscanf(line
, "%*u " /* id - discarded */
498 "%*u " /* parent - discarded */
499 "%u:%u " /* dev major:minor */
500 "%n%*s%n " /* mountroot */
501 "%n%*s%n" /* target, start and end */
502 "%c", /* more data... */
504 &mntroot_s
, &mntroot_e
,
505 &target_s
, &target_e
,
508 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
511 /* skip optional fields, terminated by " - " */
512 dash
= strstr (line
+ target_e
, " - ");
516 rc
= sscanf(dash
, " - "
517 "%n%*s%n " /* FS type, start and end */
518 "%n%*s%n " /* source, start and end */
519 "%c", /* more data... */
521 &source_s
, &source_e
,
523 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
526 /* manipulate the sub-strings in place. */
527 line
[mntroot_e
] = '\0';
528 line
[target_e
] = '\0';
530 dash
[source_e
] = '\0';
531 unescape_tab (dash
+ source_s
);
532 unescape_tab (line
+ target_s
);
533 unescape_tab (line
+ mntroot_s
);
535 me
= xmalloc (sizeof *me
);
537 me
->me_devname
= xstrdup (dash
+ source_s
);
538 me
->me_mountdir
= xstrdup (line
+ target_s
);
539 me
->me_mntroot
= xstrdup (line
+ mntroot_s
);
540 me
->me_type
= xstrdup (dash
+ type_s
);
541 me
->me_type_malloced
= 1;
542 me
->me_dev
= makedev (devmaj
, devmin
);
543 /* we pass "false" for the "Bind" option as that's only
544 significant when the Fs_type is "none" which will not be
545 the case when parsing "/proc/self/mountinfo", and only
546 applies for static /etc/mtab files. */
547 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
548 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
550 /* Add to the linked list. */
552 mtail
= &me
->me_next
;
559 int saved_errno
= errno
;
565 if (fclose (fp
) == EOF
)
568 else /* fallback to /proc/self/mounts (/etc/mtab). */
569 # endif /* __linux __ */
572 char const *table
= MOUNTED
;
574 fp
= setmntent (table
, "r");
578 while ((mnt
= getmntent (fp
)))
580 bool bind
= hasmntopt (mnt
, "bind");
582 me
= xmalloc (sizeof *me
);
583 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
584 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
585 me
->me_mntroot
= NULL
;
586 me
->me_type
= xstrdup (mnt
->mnt_type
);
587 me
->me_type_malloced
= 1;
588 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
589 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
590 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
592 /* Add to the linked list. */
594 mtail
= &me
->me_next
;
597 if (endmntent (fp
) == 0)
601 #endif /* MOUNTED_GETMNTENT1. */
603 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
608 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
611 for (; entries
-- > 0; fsp
++)
613 char *fs_type
= fsp_to_string (fsp
);
615 me
= xmalloc (sizeof *me
);
616 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
617 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
618 me
->me_mntroot
= NULL
;
619 me
->me_type
= fs_type
;
620 me
->me_type_malloced
= 0;
621 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
622 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
623 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
625 /* Add to the linked list. */
627 mtail
= &me
->me_next
;
630 #endif /* MOUNTED_GETMNTINFO */
632 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
637 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
640 for (; entries
-- > 0; fsp
++)
642 me
= xmalloc (sizeof *me
);
643 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
644 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
645 me
->me_mntroot
= NULL
;
646 me
->me_type
= xstrdup (fsp
->f_fstypename
);
647 me
->me_type_malloced
= 1;
648 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
649 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
650 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
652 /* Add to the linked list. */
654 mtail
= &me
->me_next
;
657 #endif /* MOUNTED_GETMNTINFO2 */
659 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
666 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
669 me
= xmalloc (sizeof *me
);
670 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
671 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
672 me
->me_mntroot
= NULL
;
673 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
674 me
->me_type_malloced
= 0;
675 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
676 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
677 me
->me_dev
= fsd
.fd_req
.dev
;
679 /* Add to the linked list. */
681 mtail
= &me
->me_next
;
686 #endif /* MOUNTED_GETMNT. */
688 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
690 /* The next_dev() and fs_stat_dev() system calls give the list of
691 all file systems, including the information returned by statvfs()
692 (fs type, total blocks, free blocks etc.), but without the mount
693 point. But on BeOS all file systems except / are mounted in the
694 rootfs, directly under /.
695 The directory name of the mount point is often, but not always,
696 identical to the volume name of the device.
697 We therefore get the list of subdirectories of /, and the list
698 of all file systems, and match the two lists. */
706 struct rootdir_entry
*next
;
708 struct rootdir_entry
*rootdir_list
;
709 struct rootdir_entry
**rootdir_tail
;
714 /* All volumes are mounted in the rootfs, directly under /. */
716 rootdir_tail
= &rootdir_list
;
717 dirp
= opendir ("/");
722 while ((d
= readdir (dirp
)) != NULL
)
727 if (strcmp (d
->d_name
, "..") == 0)
730 if (strcmp (d
->d_name
, ".") == 0)
731 name
= xstrdup ("/");
734 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
736 strcpy (name
+ 1, d
->d_name
);
739 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
741 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
743 re
->dev
= statbuf
.st_dev
;
744 re
->ino
= statbuf
.st_ino
;
746 /* Add to the linked list. */
748 rootdir_tail
= &re
->next
;
755 *rootdir_tail
= NULL
;
757 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
758 if (fs_stat_dev (dev
, &fi
) >= 0)
760 /* Note: fi.dev == dev. */
761 struct rootdir_entry
*re
;
763 for (re
= rootdir_list
; re
; re
= re
->next
)
764 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
767 me
= xmalloc (sizeof *me
);
768 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
769 ? fi
.device_name
: fi
.fsh_name
);
770 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
771 me
->me_mntroot
= NULL
;
772 me
->me_type
= xstrdup (fi
.fsh_name
);
773 me
->me_type_malloced
= 1;
776 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
778 /* Add to the linked list. */
780 mtail
= &me
->me_next
;
784 while (rootdir_list
!= NULL
)
786 struct rootdir_entry
*re
= rootdir_list
;
787 rootdir_list
= re
->next
;
792 #endif /* MOUNTED_FS_STAT_DEV */
794 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
798 struct statfs
*stats
;
800 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
803 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
806 bufsize
= (1 + numsys
) * sizeof *stats
;
807 stats
= xmalloc (bufsize
);
808 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
816 for (counter
= 0; counter
< numsys
; counter
++)
818 me
= xmalloc (sizeof *me
);
819 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
820 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
821 me
->me_mntroot
= NULL
;
822 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
823 me
->me_type_malloced
= 1;
824 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
825 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
826 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
828 /* Add to the linked list. */
830 mtail
= &me
->me_next
;
835 #endif /* MOUNTED_GETFSSTAT */
837 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
840 char *table
= "/etc/mnttab";
843 fp
= fopen (table
, "r");
847 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
849 me
= xmalloc (sizeof *me
);
850 me
->me_devname
= xstrdup (mnt
.mt_dev
);
851 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
852 me
->me_mntroot
= NULL
;
853 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
855 me
->me_type_malloced
= 0;
859 char typebuf
[FSTYPSZ
];
861 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
862 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
864 me
->me_type
= xstrdup (typebuf
);
865 me
->me_type_malloced
= 1;
868 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
869 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
871 /* Add to the linked list. */
873 mtail
= &me
->me_next
;
878 /* The last fread() call must have failed. */
879 int saved_errno
= errno
;
885 if (fclose (fp
) == EOF
)
888 #endif /* MOUNTED_FREAD_FSTYP. */
890 #ifdef MOUNTED_GETMNTTBL /* (obsolete) DolphinOS */
892 struct mntent
**mnttbl
= getmnttbl (), **ent
;
893 for (ent
= mnttbl
; *ent
; ent
++)
895 me
= xmalloc (sizeof *me
);
896 me
->me_devname
= xstrdup ((*ent
)->mt_resource
);
897 me
->me_mountdir
= xstrdup ((*ent
)->mt_directory
);
898 me
->me_mntroot
= NULL
;
899 me
->me_type
= xstrdup ((*ent
)->mt_fstype
);
900 me
->me_type_malloced
= 1;
901 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
902 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
903 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
905 /* Add to the linked list. */
907 mtail
= &me
->me_next
;
911 #endif /* MOUNTED_GETMNTTBL */
913 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
915 struct extmnttab mnt
;
916 const char *table
= MNTTAB
;
920 /* No locking is needed, because the contents of /etc/mnttab is generated
924 fp
= fopen (table
, "r");
929 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
931 me
= xmalloc (sizeof *me
);
932 me
->me_devname
= xstrdup (mnt
.mnt_special
);
933 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
934 me
->me_mntroot
= NULL
;
935 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
936 me
->me_type_malloced
= 1;
937 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
938 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
939 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
941 /* Add to the linked list. */
943 mtail
= &me
->me_next
;
946 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
947 /* Here ret = -1 means success, ret >= 0 means failure. */
956 #endif /* MOUNTED_GETMNTTBL */
958 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
961 const char *table
= MNTTAB
;
966 # if defined F_RDLCK && defined F_SETLKW
967 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
968 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
969 for this file name, we should use their macro name instead.
970 (Why not just lock MNTTAB directly? We don't know.) */
972 # define MNTTAB_LOCK "/etc/.mnttab.lock"
974 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
978 flock
.l_type
= F_RDLCK
;
979 flock
.l_whence
= SEEK_SET
;
982 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
985 int saved_errno
= errno
;
991 else if (errno
!= ENOENT
)
996 fp
= fopen (table
, "r");
1001 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1003 me
= xmalloc (sizeof *me
);
1004 me
->me_devname
= xstrdup (mnt
.mnt_special
);
1005 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
1006 me
->me_mntroot
= NULL
;
1007 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
1008 me
->me_type_malloced
= 1;
1009 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1010 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1011 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1013 /* Add to the linked list. */
1015 mtail
= &me
->me_next
;
1018 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1019 /* Here ret = -1 means success, ret >= 0 means failure. */
1022 if (0 <= lockfd
&& close (lockfd
) != 0)
1028 goto free_then_fail
;
1031 #endif /* MOUNTED_GETMNTENT2. */
1033 #ifdef MOUNTED_VMOUNT /* AIX */
1042 /* Ask how many bytes to allocate for the mounted file system info. */
1044 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
1046 entries
= xmalloc (bufsize
);
1048 /* Get the list of mounted file systems. */
1049 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1052 int saved_errno
= errno
;
1054 errno
= saved_errno
;
1058 for (i
= 0, thisent
= entries
;
1060 i
++, thisent
+= vmp
->vmt_length
)
1062 char *options
, *ignore
;
1064 vmp
= (struct vmount
*) thisent
;
1065 me
= xmalloc (sizeof *me
);
1066 if (vmp
->vmt_flags
& MNT_REMOTE
)
1071 /* Prepend the remote dirname. */
1072 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1073 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1074 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1075 strcpy (me
->me_devname
, host
);
1076 strcat (me
->me_devname
, ":");
1077 strcat (me
->me_devname
, dir
);
1082 me
->me_devname
= xstrdup (thisent
+
1083 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1085 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1086 me
->me_mntroot
= NULL
;
1087 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1088 me
->me_type_malloced
= 1;
1089 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1090 ignore
= strstr (options
, "ignore");
1091 me
->me_dummy
= (ignore
1092 && (ignore
== options
|| ignore
[-1] == ',')
1093 && (ignore
[sizeof "ignore" - 1] == ','
1094 || ignore
[sizeof "ignore" - 1] == '\0'));
1095 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1097 /* Add to the linked list. */
1099 mtail
= &me
->me_next
;
1103 #endif /* MOUNTED_VMOUNT. */
1105 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1107 DIR *dirp
= opendir ("/dev/fs");
1108 char node
[9 + NAME_MAX
];
1111 goto free_then_fail
;
1116 struct dirent entry
;
1117 struct dirent
*result
;
1119 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1120 marked obsolescent in glibc. Use readdir instead. */
1121 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1124 strcpy (node
, "/dev/fs/");
1125 strcat (node
, entry
.d_name
);
1127 if (statvfs (node
, &dev
) == 0)
1129 me
= xmalloc (sizeof *me
);
1130 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1131 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1132 me
->me_mntroot
= NULL
;
1133 me
->me_type
= xstrdup (dev
.f_fstypename
);
1134 me
->me_type_malloced
= 1;
1135 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1136 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1137 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1139 /* Add to the linked list. */
1141 mtail
= &me
->me_next
;
1146 #endif /* MOUNTED_INTERIX_STATVFS */
1152 free_then_fail
: _GL_UNUSED_LABEL
1154 int saved_errno
= errno
;
1159 me
= mount_list
->me_next
;
1160 free_mount_entry (mount_list
);
1164 errno
= saved_errno
;
1169 /* Free a mount entry as returned from read_file_system_list (). */
1171 void free_mount_entry (struct mount_entry
*me
)
1173 free (me
->me_devname
);
1174 free (me
->me_mountdir
);
1175 free (me
->me_mntroot
);
1176 if (me
->me_type_malloced
)