1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991-1992, 1997-2019 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
20 #include "mountlist.h"
37 # include <sys/param.h>
41 # include <sys/mkdev.h>
42 #elif MAJOR_IN_SYSMACROS
43 # include <sys/sysmacros.h>
46 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
48 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
49 NGROUPS is used as an array dimension in ucred.h */
50 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
53 # include <sys/mount.h>
55 # if HAVE_SYS_FS_TYPES_H
56 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
58 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
59 # define FS_TYPE(Ent) ((Ent).f_fstypename)
61 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
63 #endif /* MOUNTED_GETFSSTAT */
65 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
66 also (obsolete) 4.3BSD, SunOS */
68 # include <sys/types.h>
69 # if defined __ANDROID__ /* Android */
70 /* Bionic versions from between 2014-01-09 and 2015-01-08 define MOUNTED to
71 an incorrect value; older Bionic versions don't define it at all. */
73 # define MOUNTED "/proc/mounts"
74 # elif !defined MOUNTED
75 # if defined _PATH_MOUNTED /* GNU libc */
76 # define MOUNTED _PATH_MOUNTED
78 # if defined MNT_MNTTAB /* HP-UX. */
79 # define MOUNTED MNT_MNTTAB
84 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
85 # include <sys/mount.h>
88 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
89 # include <sys/statvfs.h>
92 #ifdef MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
97 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
99 # include <sys/fstyp.h>
100 # include <sys/statfs.h>
103 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
104 # include <sys/mnttab.h>
107 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
108 # include <sys/mnttab.h>
111 #ifdef MOUNTED_VMOUNT /* AIX */
113 # include <sys/vfs.h>
116 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
117 # include <sys/statvfs.h>
121 #if HAVE_SYS_MNTENT_H
122 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
123 # include <sys/mntent.h>
126 #ifdef MOUNTED_GETMNTENT1
127 # if !HAVE_SETMNTENT /* Android <= 4.4 */
128 # define setmntent(fp,mode) fopen (fp, mode)
130 # if !HAVE_ENDMNTENT /* Android <= 4.4 */
131 # define endmntent(fp) fclose (fp)
135 #ifndef HAVE_HASMNTOPT
136 # define hasmntopt(mnt, opt) ((char *) 0)
141 # if defined __sun && defined __SVR4
142 /* Solaris defines hasmntopt(struct mnttab *, char *)
143 while it is otherwise hasmntopt(struct mnttab *, const char *). */
144 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
146 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
149 # define MNT_IGNORE(M) 0
153 # include "unlocked-io.h"
156 /* The results of opendir() in this file are not used with dirfd and fchdir,
157 therefore save some unnecessary work in fchdir.c. */
158 #ifdef GNULIB_defined_opendir
161 #ifdef GNULIB_defined_closedir
165 #define ME_DUMMY_0(Fs_name, Fs_type) \
166 (strcmp (Fs_type, "autofs") == 0 \
167 || strcmp (Fs_type, "proc") == 0 \
168 || strcmp (Fs_type, "subfs") == 0 \
169 /* for Linux 2.6/3.x */ \
170 || strcmp (Fs_type, "debugfs") == 0 \
171 || strcmp (Fs_type, "devpts") == 0 \
172 || strcmp (Fs_type, "fusectl") == 0 \
173 || strcmp (Fs_type, "mqueue") == 0 \
174 || strcmp (Fs_type, "rpc_pipefs") == 0 \
175 || strcmp (Fs_type, "sysfs") == 0 \
176 /* FreeBSD, Linux 2.4 */ \
177 || strcmp (Fs_type, "devfs") == 0 \
178 /* for NetBSD 3.0 */ \
179 || strcmp (Fs_type, "kernfs") == 0 \
181 || strcmp (Fs_type, "ignore") == 0)
183 /* Historically, we have marked as "dummy" any file system of type "none",
184 but now that programs like du need to know about bind-mounted directories,
185 we grant an exception to any with "bind" in its list of mount options.
186 I.e., those are *not* dummy entries. */
187 #ifdef MOUNTED_GETMNTENT1
188 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
189 (ME_DUMMY_0 (Fs_name, Fs_type) \
190 || (strcmp (Fs_type, "none") == 0 && !Bind))
192 # define ME_DUMMY(Fs_name, Fs_type) \
193 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
197 # include <windows.h>
198 # define ME_REMOTE me_remote
199 /* All cygwin mount points include ':' or start with '//'; so it
200 requires a native Windows call to determine remote disks. */
202 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
204 if (fs_name
[0] && fs_name
[1] == ':')
207 sprintf (drive
, "%c:\\", fs_name
[0]);
208 switch (GetDriveType (drive
))
210 case DRIVE_REMOVABLE
:
222 /* A file system is "remote" if its Fs_name contains a ':'
223 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
224 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
225 # define ME_REMOTE(Fs_name, Fs_type) \
226 (strchr (Fs_name, ':') != NULL \
227 || ((Fs_name)[0] == '/' \
228 && (Fs_name)[1] == '/' \
229 && (strcmp (Fs_type, "smbfs") == 0 \
230 || strcmp (Fs_type, "cifs") == 0)) \
231 || (strcmp("-hosts", Fs_name) == 0))
234 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
236 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
238 fstype_to_string (short int t
)
333 fsp_to_string (const struct statfs
*fsp
)
335 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
336 return (char *) (fsp
->f_fstypename
);
338 return fstype_to_string (fsp
->f_type
);
342 #endif /* MOUNTED_GETMNTINFO */
344 #ifdef MOUNTED_VMOUNT /* AIX */
346 fstype_to_string (int t
)
350 e
= getvfsbytype (t
);
351 if (!e
|| !e
->vfsent_name
)
354 return e
->vfsent_name
;
356 #endif /* MOUNTED_VMOUNT */
359 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
361 /* Return the device number from MOUNT_OPTIONS, if possible.
362 Otherwise return (dev_t) -1. */
364 dev_from_mount_options (char const *mount_options
)
366 /* GNU/Linux allows file system implementations to define their own
367 meaning for "dev=" mount options, so don't trust the meaning
371 static char const dev_pattern
[] = ",dev=";
372 char const *devopt
= strstr (mount_options
, dev_pattern
);
376 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
378 unsigned long int dev
;
380 dev
= strtoul (optval
, &optvalend
, 16);
381 if (optval
!= optvalend
382 && (*optvalend
== '\0' || *optvalend
== ',')
383 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
384 && dev
== (dev_t
) dev
)
389 (void) mount_options
;
395 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
397 /* Unescape the paths in mount tables.
398 STR is updated in place. */
401 unescape_tab (char *str
)
404 size_t len
= strlen (str
) + 1;
405 for (i
= 0; i
< len
; i
++)
407 if (str
[i
] == '\\' && (i
+ 4 < len
)
408 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
409 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
410 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
412 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
413 (str
[i
+ 2] - '0') * 8 +
423 /* Return a list of the currently mounted file systems, or NULL on error.
424 Add each entry to the tail of the list so that they stay in order.
425 If NEED_FS_TYPE is true, ensure that the file system type fields in
426 the returned list are valid. Otherwise, they might not be. */
429 read_file_system_list (bool need_fs_type
)
431 struct mount_entry
*mount_list
;
432 struct mount_entry
*me
;
433 struct mount_entry
**mtail
= &mount_list
;
436 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
437 also (obsolete) 4.3BSD, SunOS */
441 # if defined __linux__ || defined __ANDROID__
442 /* Try parsing mountinfo first, as that make device IDs available.
443 Note we could use libmount routines to simplify this parsing a little
444 (and that code is in previous versions of this function), however
445 libmount depends on libselinux which pulls in many dependencies. */
446 char const *mountinfo
= "/proc/self/mountinfo";
447 fp
= fopen (mountinfo
, "r");
453 while (getline (&line
, &buf_size
, fp
) != -1)
455 unsigned int devmaj
, devmin
;
456 int target_s
, target_e
, type_s
, type_e
;
457 int source_s
, source_e
, mntroot_s
, mntroot_e
;
462 rc
= sscanf(line
, "%*u " /* id - discarded */
463 "%*u " /* parent - discarded */
464 "%u:%u " /* dev major:minor */
465 "%n%*s%n " /* mountroot */
466 "%n%*s%n" /* target, start and end */
467 "%c", /* more data... */
469 &mntroot_s
, &mntroot_e
,
470 &target_s
, &target_e
,
473 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
476 /* skip optional fields, terminated by " - " */
477 dash
= strstr (line
+ target_e
, " - ");
481 rc
= sscanf(dash
, " - "
482 "%n%*s%n " /* FS type, start and end */
483 "%n%*s%n " /* source, start and end */
484 "%c", /* more data... */
486 &source_s
, &source_e
,
488 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
491 /* manipulate the sub-strings in place. */
492 line
[mntroot_e
] = '\0';
493 line
[target_e
] = '\0';
495 dash
[source_e
] = '\0';
496 unescape_tab (dash
+ source_s
);
497 unescape_tab (line
+ target_s
);
498 unescape_tab (line
+ mntroot_s
);
500 me
= xmalloc (sizeof *me
);
502 me
->me_devname
= xstrdup (dash
+ source_s
);
503 me
->me_mountdir
= xstrdup (line
+ target_s
);
504 me
->me_mntroot
= xstrdup (line
+ mntroot_s
);
505 me
->me_type
= xstrdup (dash
+ type_s
);
506 me
->me_type_malloced
= 1;
507 me
->me_dev
= makedev (devmaj
, devmin
);
508 /* we pass "false" for the "Bind" option as that's only
509 significant when the Fs_type is "none" which will not be
510 the case when parsing "/proc/self/mountinfo", and only
511 applies for static /etc/mtab files. */
512 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
513 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
515 /* Add to the linked list. */
517 mtail
= &me
->me_next
;
524 int saved_errno
= errno
;
530 if (fclose (fp
) == EOF
)
533 else /* fallback to /proc/self/mounts (/etc/mtab). */
534 # endif /* __linux __ || __ANDROID__ */
537 char const *table
= MOUNTED
;
539 fp
= setmntent (table
, "r");
543 while ((mnt
= getmntent (fp
)))
545 bool bind
= hasmntopt (mnt
, "bind");
547 me
= xmalloc (sizeof *me
);
548 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
549 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
550 me
->me_mntroot
= NULL
;
551 me
->me_type
= xstrdup (mnt
->mnt_type
);
552 me
->me_type_malloced
= 1;
553 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
554 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
555 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
557 /* Add to the linked list. */
559 mtail
= &me
->me_next
;
562 if (endmntent (fp
) == 0)
566 #endif /* MOUNTED_GETMNTENT1. */
568 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
573 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
576 for (; entries
-- > 0; fsp
++)
578 char *fs_type
= fsp_to_string (fsp
);
580 me
= xmalloc (sizeof *me
);
581 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
582 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
583 me
->me_mntroot
= NULL
;
584 me
->me_type
= fs_type
;
585 me
->me_type_malloced
= 0;
586 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
587 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
588 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
590 /* Add to the linked list. */
592 mtail
= &me
->me_next
;
595 #endif /* MOUNTED_GETMNTINFO */
597 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
602 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
605 for (; entries
-- > 0; fsp
++)
607 me
= xmalloc (sizeof *me
);
608 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
609 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
610 me
->me_mntroot
= NULL
;
611 me
->me_type
= xstrdup (fsp
->f_fstypename
);
612 me
->me_type_malloced
= 1;
613 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
614 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
615 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
617 /* Add to the linked list. */
619 mtail
= &me
->me_next
;
622 #endif /* MOUNTED_GETMNTINFO2 */
624 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
626 /* The next_dev() and fs_stat_dev() system calls give the list of
627 all file systems, including the information returned by statvfs()
628 (fs type, total blocks, free blocks etc.), but without the mount
629 point. But on BeOS all file systems except / are mounted in the
630 rootfs, directly under /.
631 The directory name of the mount point is often, but not always,
632 identical to the volume name of the device.
633 We therefore get the list of subdirectories of /, and the list
634 of all file systems, and match the two lists. */
642 struct rootdir_entry
*next
;
644 struct rootdir_entry
*rootdir_list
;
645 struct rootdir_entry
**rootdir_tail
;
650 /* All volumes are mounted in the rootfs, directly under /. */
652 rootdir_tail
= &rootdir_list
;
653 dirp
= opendir ("/");
658 while ((d
= readdir (dirp
)) != NULL
)
663 if (strcmp (d
->d_name
, "..") == 0)
666 if (strcmp (d
->d_name
, ".") == 0)
667 name
= xstrdup ("/");
670 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
672 strcpy (name
+ 1, d
->d_name
);
675 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
677 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
679 re
->dev
= statbuf
.st_dev
;
680 re
->ino
= statbuf
.st_ino
;
682 /* Add to the linked list. */
684 rootdir_tail
= &re
->next
;
691 *rootdir_tail
= NULL
;
693 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
694 if (fs_stat_dev (dev
, &fi
) >= 0)
696 /* Note: fi.dev == dev. */
697 struct rootdir_entry
*re
;
699 for (re
= rootdir_list
; re
; re
= re
->next
)
700 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
703 me
= xmalloc (sizeof *me
);
704 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
705 ? fi
.device_name
: fi
.fsh_name
);
706 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
707 me
->me_mntroot
= NULL
;
708 me
->me_type
= xstrdup (fi
.fsh_name
);
709 me
->me_type_malloced
= 1;
712 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
714 /* Add to the linked list. */
716 mtail
= &me
->me_next
;
720 while (rootdir_list
!= NULL
)
722 struct rootdir_entry
*re
= rootdir_list
;
723 rootdir_list
= re
->next
;
728 #endif /* MOUNTED_FS_STAT_DEV */
730 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
734 struct statfs
*stats
;
736 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
739 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
742 bufsize
= (1 + numsys
) * sizeof *stats
;
743 stats
= xmalloc (bufsize
);
744 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
752 for (counter
= 0; counter
< numsys
; counter
++)
754 me
= xmalloc (sizeof *me
);
755 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
756 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
757 me
->me_mntroot
= NULL
;
758 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
759 me
->me_type_malloced
= 1;
760 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
761 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
762 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
764 /* Add to the linked list. */
766 mtail
= &me
->me_next
;
771 #endif /* MOUNTED_GETFSSTAT */
773 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
776 char *table
= "/etc/mnttab";
779 fp
= fopen (table
, "r");
783 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
785 me
= xmalloc (sizeof *me
);
786 me
->me_devname
= xstrdup (mnt
.mt_dev
);
787 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
788 me
->me_mntroot
= NULL
;
789 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
791 me
->me_type_malloced
= 0;
795 char typebuf
[FSTYPSZ
];
797 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
798 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
800 me
->me_type
= xstrdup (typebuf
);
801 me
->me_type_malloced
= 1;
804 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
805 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
807 /* Add to the linked list. */
809 mtail
= &me
->me_next
;
814 /* The last fread() call must have failed. */
815 int saved_errno
= errno
;
821 if (fclose (fp
) == EOF
)
824 #endif /* MOUNTED_FREAD_FSTYP. */
826 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
828 struct extmnttab mnt
;
829 const char *table
= MNTTAB
;
833 /* No locking is needed, because the contents of /etc/mnttab is generated
837 fp
= fopen (table
, "r");
842 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
844 me
= xmalloc (sizeof *me
);
845 me
->me_devname
= xstrdup (mnt
.mnt_special
);
846 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
847 me
->me_mntroot
= NULL
;
848 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
849 me
->me_type_malloced
= 1;
850 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
851 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
852 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
854 /* Add to the linked list. */
856 mtail
= &me
->me_next
;
859 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
860 /* Here ret = -1 means success, ret >= 0 means failure. */
869 #endif /* MOUNTED_GETEXTMNTENT */
871 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
874 const char *table
= MNTTAB
;
879 # if defined F_RDLCK && defined F_SETLKW
880 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
881 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
882 for this file name, we should use their macro name instead.
883 (Why not just lock MNTTAB directly? We don't know.) */
885 # define MNTTAB_LOCK "/etc/.mnttab.lock"
887 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
891 flock
.l_type
= F_RDLCK
;
892 flock
.l_whence
= SEEK_SET
;
895 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
898 int saved_errno
= errno
;
904 else if (errno
!= ENOENT
)
909 fp
= fopen (table
, "r");
914 while ((ret
= getmntent (fp
, &mnt
)) == 0)
916 me
= xmalloc (sizeof *me
);
917 me
->me_devname
= xstrdup (mnt
.mnt_special
);
918 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
919 me
->me_mntroot
= NULL
;
920 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
921 me
->me_type_malloced
= 1;
922 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
923 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
924 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
926 /* Add to the linked list. */
928 mtail
= &me
->me_next
;
931 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
932 /* Here ret = -1 means success, ret >= 0 means failure. */
935 if (0 <= lockfd
&& close (lockfd
) != 0)
944 #endif /* MOUNTED_GETMNTENT2. */
946 #ifdef MOUNTED_VMOUNT /* AIX */
955 /* Ask how many bytes to allocate for the mounted file system info. */
957 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
959 entries
= xmalloc (bufsize
);
961 /* Get the list of mounted file systems. */
962 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
965 int saved_errno
= errno
;
971 for (i
= 0, thisent
= entries
;
973 i
++, thisent
+= vmp
->vmt_length
)
975 char *options
, *ignore
;
977 vmp
= (struct vmount
*) thisent
;
978 me
= xmalloc (sizeof *me
);
979 if (vmp
->vmt_flags
& MNT_REMOTE
)
984 /* Prepend the remote dirname. */
985 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
986 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
987 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
988 strcpy (me
->me_devname
, host
);
989 strcat (me
->me_devname
, ":");
990 strcat (me
->me_devname
, dir
);
995 me
->me_devname
= xstrdup (thisent
+
996 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
998 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
999 me
->me_mntroot
= NULL
;
1000 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1001 me
->me_type_malloced
= 1;
1002 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1003 ignore
= strstr (options
, "ignore");
1004 me
->me_dummy
= (ignore
1005 && (ignore
== options
|| ignore
[-1] == ',')
1006 && (ignore
[sizeof "ignore" - 1] == ','
1007 || ignore
[sizeof "ignore" - 1] == '\0'));
1008 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1010 /* Add to the linked list. */
1012 mtail
= &me
->me_next
;
1016 #endif /* MOUNTED_VMOUNT. */
1018 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1020 DIR *dirp
= opendir ("/dev/fs");
1021 char node
[9 + NAME_MAX
];
1024 goto free_then_fail
;
1029 struct dirent entry
;
1030 struct dirent
*result
;
1032 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1033 marked obsolescent in glibc. Use readdir instead. */
1034 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1037 strcpy (node
, "/dev/fs/");
1038 strcat (node
, entry
.d_name
);
1040 if (statvfs (node
, &dev
) == 0)
1042 me
= xmalloc (sizeof *me
);
1043 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1044 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1045 me
->me_mntroot
= NULL
;
1046 me
->me_type
= xstrdup (dev
.f_fstypename
);
1047 me
->me_type_malloced
= 1;
1048 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1049 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1050 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1052 /* Add to the linked list. */
1054 mtail
= &me
->me_next
;
1059 #endif /* MOUNTED_INTERIX_STATVFS */
1065 free_then_fail
: _GL_UNUSED_LABEL
1067 int saved_errno
= errno
;
1072 me
= mount_list
->me_next
;
1073 free_mount_entry (mount_list
);
1077 errno
= saved_errno
;
1082 /* Free a mount entry as returned from read_file_system_list (). */
1084 void free_mount_entry (struct mount_entry
*me
)
1086 free (me
->me_devname
);
1087 free (me
->me_mountdir
);
1088 free (me
->me_mntroot
);
1089 if (me
->me_type_malloced
)