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 /* (obsolete) SVR2 */
104 #ifdef MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
106 # include <sys/fstyp.h>
107 # include <sys/statfs.h>
110 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
114 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
115 # include <sys/mnttab.h>
118 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
119 # include <sys/mnttab.h>
122 #ifdef MOUNTED_VMOUNT /* AIX */
124 # include <sys/vfs.h>
127 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
128 # include <sys/statvfs.h>
133 /* So special that it's not worth putting this in autoconf. */
134 # undef MOUNTED_FREAD_FSTYP
135 # define MOUNTED_GETMNTTBL
138 #if HAVE_SYS_MNTENT_H
139 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
140 # include <sys/mntent.h>
143 #ifndef HAVE_HASMNTOPT
144 # define hasmntopt(mnt, opt) ((char *) 0)
149 # if defined __sun && defined __SVR4
150 /* Solaris defines hasmntopt(struct mnttab *, char *)
151 while it is otherwise hasmntopt(struct mnttab *, const char *). */
152 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
154 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
157 # define MNT_IGNORE(M) 0
161 # include "unlocked-io.h"
164 /* The results of opendir() in this file are not used with dirfd and fchdir,
165 therefore save some unnecessary work in fchdir.c. */
166 #ifdef GNULIB_defined_opendir
169 #ifdef GNULIB_defined_closedir
173 #define ME_DUMMY_0(Fs_name, Fs_type) \
174 (strcmp (Fs_type, "autofs") == 0 \
175 || strcmp (Fs_type, "proc") == 0 \
176 || strcmp (Fs_type, "subfs") == 0 \
177 /* for Linux 2.6/3.x */ \
178 || strcmp (Fs_type, "debugfs") == 0 \
179 || strcmp (Fs_type, "devpts") == 0 \
180 || strcmp (Fs_type, "fusectl") == 0 \
181 || strcmp (Fs_type, "mqueue") == 0 \
182 || strcmp (Fs_type, "rpc_pipefs") == 0 \
183 || strcmp (Fs_type, "sysfs") == 0 \
184 /* FreeBSD, Linux 2.4 */ \
185 || strcmp (Fs_type, "devfs") == 0 \
186 /* for NetBSD 3.0 */ \
187 || strcmp (Fs_type, "kernfs") == 0 \
189 || strcmp (Fs_type, "ignore") == 0)
191 /* Historically, we have marked as "dummy" any file system of type "none",
192 but now that programs like du need to know about bind-mounted directories,
193 we grant an exception to any with "bind" in its list of mount options.
194 I.e., those are *not* dummy entries. */
195 #ifdef MOUNTED_GETMNTENT1
196 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
197 (ME_DUMMY_0 (Fs_name, Fs_type) \
198 || (strcmp (Fs_type, "none") == 0 && !Bind))
200 # define ME_DUMMY(Fs_name, Fs_type) \
201 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
205 # include <windows.h>
206 # define ME_REMOTE me_remote
207 /* All cygwin mount points include ':' or start with '//'; so it
208 requires a native Windows call to determine remote disks. */
210 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
212 if (fs_name
[0] && fs_name
[1] == ':')
215 sprintf (drive
, "%c:\\", fs_name
[0]);
216 switch (GetDriveType (drive
))
218 case DRIVE_REMOVABLE
:
230 /* A file system is "remote" if its Fs_name contains a ':'
231 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
232 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
233 # define ME_REMOTE(Fs_name, Fs_type) \
234 (strchr (Fs_name, ':') != NULL \
235 || ((Fs_name)[0] == '/' \
236 && (Fs_name)[1] == '/' \
237 && (strcmp (Fs_type, "smbfs") == 0 \
238 || strcmp (Fs_type, "cifs") == 0)) \
239 || (strcmp("-hosts", Fs_name) == 0))
242 #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
244 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
246 fstype_to_string (short int t
)
341 fsp_to_string (const struct statfs
*fsp
)
343 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
344 return (char *) (fsp
->f_fstypename
);
346 return fstype_to_string (fsp
->f_type
);
350 #endif /* MOUNTED_GETMNTINFO */
352 #ifdef MOUNTED_VMOUNT /* AIX */
354 fstype_to_string (int t
)
358 e
= getvfsbytype (t
);
359 if (!e
|| !e
->vfsent_name
)
362 return e
->vfsent_name
;
364 #endif /* MOUNTED_VMOUNT */
367 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
369 /* Return the device number from MOUNT_OPTIONS, if possible.
370 Otherwise return (dev_t) -1. */
372 dev_from_mount_options (char const *mount_options
)
374 /* GNU/Linux allows file system implementations to define their own
375 meaning for "dev=" mount options, so don't trust the meaning
379 static char const dev_pattern
[] = ",dev=";
380 char const *devopt
= strstr (mount_options
, dev_pattern
);
384 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
386 unsigned long int dev
;
388 dev
= strtoul (optval
, &optvalend
, 16);
389 if (optval
!= optvalend
390 && (*optvalend
== '\0' || *optvalend
== ',')
391 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
392 && dev
== (dev_t
) dev
)
397 (void) mount_options
;
403 #if defined MOUNTED_GETMNTENT1 && defined __linux__ /* GNU/Linux, Android */
405 /* Unescape the paths in mount tables.
406 STR is updated in place. */
409 unescape_tab (char *str
)
412 size_t len
= strlen (str
) + 1;
413 for (i
= 0; i
< len
; i
++)
415 if (str
[i
] == '\\' && (i
+ 4 < len
)
416 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
417 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
418 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
420 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
421 (str
[i
+ 2] - '0') * 8 +
431 /* Return a list of the currently mounted file systems, or NULL on error.
432 Add each entry to the tail of the list so that they stay in order.
433 If NEED_FS_TYPE is true, ensure that the file system type fields in
434 the returned list are valid. Otherwise, they might not be. */
437 read_file_system_list (bool need_fs_type
)
439 struct mount_entry
*mount_list
;
440 struct mount_entry
*me
;
441 struct mount_entry
**mtail
= &mount_list
;
444 #ifdef MOUNTED_LISTMNTENT /* (obsolete) Cray UNICOS 9 */
446 struct tabmntent
*mntlist
, *p
;
449 /* the third and fourth arguments could be used to filter mounts,
450 but Crays doesn't seem to have any mounts that we want to
451 remove. Specifically, automount create normal NFS mounts.
454 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
456 for (p
= mntlist
; p
; p
= p
->next
)
459 me
= xmalloc (sizeof *me
);
460 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
461 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
462 me
->me_mntroot
= NULL
;
463 me
->me_type
= xstrdup (mnt
->mnt_type
);
464 me
->me_type_malloced
= 1;
465 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
466 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
469 mtail
= &me
->me_next
;
471 freemntlist (mntlist
);
475 #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android,
476 also (obsolete) 4.3BSD, SunOS, Dynix */
481 /* Try parsing mountinfo first, as that make device IDs available.
482 Note we could use libmount routines to simplify this parsing a little
483 (and that code is in previous versions of this function), however
484 libmount depends on libselinux which pulls in many dependencies. */
485 char const *mountinfo
= "/proc/self/mountinfo";
486 fp
= fopen (mountinfo
, "r");
492 while (getline (&line
, &buf_size
, fp
) != -1)
494 unsigned int devmaj
, devmin
;
495 int target_s
, target_e
, type_s
, type_e
;
496 int source_s
, source_e
, mntroot_s
, mntroot_e
;
501 rc
= sscanf(line
, "%*u " /* id - discarded */
502 "%*u " /* parent - discarded */
503 "%u:%u " /* dev major:minor */
504 "%n%*s%n " /* mountroot */
505 "%n%*s%n" /* target, start and end */
506 "%c", /* more data... */
508 &mntroot_s
, &mntroot_e
,
509 &target_s
, &target_e
,
512 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
515 /* skip optional fields, terminated by " - " */
516 dash
= strstr (line
+ target_e
, " - ");
520 rc
= sscanf(dash
, " - "
521 "%n%*s%n " /* FS type, start and end */
522 "%n%*s%n " /* source, start and end */
523 "%c", /* more data... */
525 &source_s
, &source_e
,
527 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
530 /* manipulate the sub-strings in place. */
531 line
[mntroot_e
] = '\0';
532 line
[target_e
] = '\0';
534 dash
[source_e
] = '\0';
535 unescape_tab (dash
+ source_s
);
536 unescape_tab (line
+ target_s
);
537 unescape_tab (line
+ mntroot_s
);
539 me
= xmalloc (sizeof *me
);
541 me
->me_devname
= xstrdup (dash
+ source_s
);
542 me
->me_mountdir
= xstrdup (line
+ target_s
);
543 me
->me_mntroot
= xstrdup (line
+ mntroot_s
);
544 me
->me_type
= xstrdup (dash
+ type_s
);
545 me
->me_type_malloced
= 1;
546 me
->me_dev
= makedev (devmaj
, devmin
);
547 /* we pass "false" for the "Bind" option as that's only
548 significant when the Fs_type is "none" which will not be
549 the case when parsing "/proc/self/mountinfo", and only
550 applies for static /etc/mtab files. */
551 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
552 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
554 /* Add to the linked list. */
556 mtail
= &me
->me_next
;
563 int saved_errno
= errno
;
569 if (fclose (fp
) == EOF
)
572 else /* fallback to /proc/self/mounts (/etc/mtab). */
573 # endif /* __linux __ */
576 char const *table
= MOUNTED
;
578 fp
= setmntent (table
, "r");
582 while ((mnt
= getmntent (fp
)))
584 bool bind
= hasmntopt (mnt
, "bind");
586 me
= xmalloc (sizeof *me
);
587 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
588 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
589 me
->me_mntroot
= NULL
;
590 me
->me_type
= xstrdup (mnt
->mnt_type
);
591 me
->me_type_malloced
= 1;
592 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
593 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
594 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
596 /* Add to the linked list. */
598 mtail
= &me
->me_next
;
601 if (endmntent (fp
) == 0)
605 #endif /* MOUNTED_GETMNTENT1. */
607 #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
612 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
615 for (; entries
-- > 0; fsp
++)
617 char *fs_type
= fsp_to_string (fsp
);
619 me
= xmalloc (sizeof *me
);
620 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
621 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
622 me
->me_mntroot
= NULL
;
623 me
->me_type
= fs_type
;
624 me
->me_type_malloced
= 0;
625 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
626 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
627 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
629 /* Add to the linked list. */
631 mtail
= &me
->me_next
;
634 #endif /* MOUNTED_GETMNTINFO */
636 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */
641 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
644 for (; entries
-- > 0; fsp
++)
646 me
= xmalloc (sizeof *me
);
647 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
648 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
649 me
->me_mntroot
= NULL
;
650 me
->me_type
= xstrdup (fsp
->f_fstypename
);
651 me
->me_type_malloced
= 1;
652 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
653 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
654 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
656 /* Add to the linked list. */
658 mtail
= &me
->me_next
;
661 #endif /* MOUNTED_GETMNTINFO2 */
663 #ifdef MOUNTED_GETMNT /* (obsolete) Ultrix */
670 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
673 me
= xmalloc (sizeof *me
);
674 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
675 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
676 me
->me_mntroot
= NULL
;
677 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
678 me
->me_type_malloced
= 0;
679 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
680 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
681 me
->me_dev
= fsd
.fd_req
.dev
;
683 /* Add to the linked list. */
685 mtail
= &me
->me_next
;
690 #endif /* MOUNTED_GETMNT. */
692 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
694 /* The next_dev() and fs_stat_dev() system calls give the list of
695 all file systems, including the information returned by statvfs()
696 (fs type, total blocks, free blocks etc.), but without the mount
697 point. But on BeOS all file systems except / are mounted in the
698 rootfs, directly under /.
699 The directory name of the mount point is often, but not always,
700 identical to the volume name of the device.
701 We therefore get the list of subdirectories of /, and the list
702 of all file systems, and match the two lists. */
710 struct rootdir_entry
*next
;
712 struct rootdir_entry
*rootdir_list
;
713 struct rootdir_entry
**rootdir_tail
;
718 /* All volumes are mounted in the rootfs, directly under /. */
720 rootdir_tail
= &rootdir_list
;
721 dirp
= opendir ("/");
726 while ((d
= readdir (dirp
)) != NULL
)
731 if (strcmp (d
->d_name
, "..") == 0)
734 if (strcmp (d
->d_name
, ".") == 0)
735 name
= xstrdup ("/");
738 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
740 strcpy (name
+ 1, d
->d_name
);
743 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
745 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
747 re
->dev
= statbuf
.st_dev
;
748 re
->ino
= statbuf
.st_ino
;
750 /* Add to the linked list. */
752 rootdir_tail
= &re
->next
;
759 *rootdir_tail
= NULL
;
761 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
762 if (fs_stat_dev (dev
, &fi
) >= 0)
764 /* Note: fi.dev == dev. */
765 struct rootdir_entry
*re
;
767 for (re
= rootdir_list
; re
; re
= re
->next
)
768 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
771 me
= xmalloc (sizeof *me
);
772 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
773 ? fi
.device_name
: fi
.fsh_name
);
774 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
775 me
->me_mntroot
= NULL
;
776 me
->me_type
= xstrdup (fi
.fsh_name
);
777 me
->me_type_malloced
= 1;
780 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
782 /* Add to the linked list. */
784 mtail
= &me
->me_next
;
788 while (rootdir_list
!= NULL
)
790 struct rootdir_entry
*re
= rootdir_list
;
791 rootdir_list
= re
->next
;
796 #endif /* MOUNTED_FS_STAT_DEV */
798 #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */
802 struct statfs
*stats
;
804 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
807 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
810 bufsize
= (1 + numsys
) * sizeof *stats
;
811 stats
= xmalloc (bufsize
);
812 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
820 for (counter
= 0; counter
< numsys
; counter
++)
822 me
= xmalloc (sizeof *me
);
823 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
824 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
825 me
->me_mntroot
= NULL
;
826 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
827 me
->me_type_malloced
= 1;
828 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
829 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
830 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
832 /* Add to the linked list. */
834 mtail
= &me
->me_next
;
839 #endif /* MOUNTED_GETFSSTAT */
841 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3, SVR2 */
844 char *table
= "/etc/mnttab";
847 fp
= fopen (table
, "r");
851 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
853 me
= xmalloc (sizeof *me
);
854 # ifdef GETFSTYP /* SVR3. */
855 me
->me_devname
= xstrdup (mnt
.mt_dev
);
857 me
->me_devname
= xmalloc (strlen (mnt
.mt_dev
) + 6);
858 strcpy (me
->me_devname
, "/dev/");
859 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
861 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
862 me
->me_mntroot
= NULL
;
863 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
865 me
->me_type_malloced
= 0;
866 # ifdef GETFSTYP /* SVR3. */
870 char typebuf
[FSTYPSZ
];
872 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
873 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
875 me
->me_type
= xstrdup (typebuf
);
876 me
->me_type_malloced
= 1;
880 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
881 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
883 /* Add to the linked list. */
885 mtail
= &me
->me_next
;
890 /* The last fread() call must have failed. */
891 int saved_errno
= errno
;
897 if (fclose (fp
) == EOF
)
900 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
902 #ifdef MOUNTED_GETMNTTBL /* (obsolete) DolphinOS */
904 struct mntent
**mnttbl
= getmnttbl (), **ent
;
905 for (ent
= mnttbl
; *ent
; ent
++)
907 me
= xmalloc (sizeof *me
);
908 me
->me_devname
= xstrdup ((*ent
)->mt_resource
);
909 me
->me_mountdir
= xstrdup ((*ent
)->mt_directory
);
910 me
->me_mntroot
= NULL
;
911 me
->me_type
= xstrdup ((*ent
)->mt_fstype
);
912 me
->me_type_malloced
= 1;
913 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
914 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
915 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
917 /* Add to the linked list. */
919 mtail
= &me
->me_next
;
923 #endif /* MOUNTED_GETMNTTBL */
925 #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */
927 struct extmnttab mnt
;
928 const char *table
= MNTTAB
;
932 /* No locking is needed, because the contents of /etc/mnttab is generated
936 fp
= fopen (table
, "r");
941 while ((ret
= getextmntent (fp
, &mnt
, 1)) == 0)
943 me
= xmalloc (sizeof *me
);
944 me
->me_devname
= xstrdup (mnt
.mnt_special
);
945 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
946 me
->me_mntroot
= NULL
;
947 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
948 me
->me_type_malloced
= 1;
949 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
950 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
951 me
->me_dev
= makedev (mnt
.mnt_major
, mnt
.mnt_minor
);
953 /* Add to the linked list. */
955 mtail
= &me
->me_next
;
958 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
959 /* Here ret = -1 means success, ret >= 0 means failure. */
968 #endif /* MOUNTED_GETMNTTBL */
970 #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */
973 const char *table
= MNTTAB
;
978 # if defined F_RDLCK && defined F_SETLKW
979 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
980 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
981 for this file name, we should use their macro name instead.
982 (Why not just lock MNTTAB directly? We don't know.) */
984 # define MNTTAB_LOCK "/etc/.mnttab.lock"
986 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
990 flock
.l_type
= F_RDLCK
;
991 flock
.l_whence
= SEEK_SET
;
994 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
997 int saved_errno
= errno
;
1003 else if (errno
!= ENOENT
)
1008 fp
= fopen (table
, "r");
1013 while ((ret
= getmntent (fp
, &mnt
)) == 0)
1015 me
= xmalloc (sizeof *me
);
1016 me
->me_devname
= xstrdup (mnt
.mnt_special
);
1017 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
1018 me
->me_mntroot
= NULL
;
1019 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
1020 me
->me_type_malloced
= 1;
1021 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
1022 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1023 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
1025 /* Add to the linked list. */
1027 mtail
= &me
->me_next
;
1030 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
1031 /* Here ret = -1 means success, ret >= 0 means failure. */
1034 if (0 <= lockfd
&& close (lockfd
) != 0)
1040 goto free_then_fail
;
1043 #endif /* MOUNTED_GETMNTENT2. */
1045 #ifdef MOUNTED_VMOUNT /* AIX */
1054 /* Ask how many bytes to allocate for the mounted file system info. */
1056 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
1058 entries
= xmalloc (bufsize
);
1060 /* Get the list of mounted file systems. */
1061 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1064 int saved_errno
= errno
;
1066 errno
= saved_errno
;
1070 for (i
= 0, thisent
= entries
;
1072 i
++, thisent
+= vmp
->vmt_length
)
1074 char *options
, *ignore
;
1076 vmp
= (struct vmount
*) thisent
;
1077 me
= xmalloc (sizeof *me
);
1078 if (vmp
->vmt_flags
& MNT_REMOTE
)
1083 /* Prepend the remote dirname. */
1084 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1085 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1086 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1087 strcpy (me
->me_devname
, host
);
1088 strcat (me
->me_devname
, ":");
1089 strcat (me
->me_devname
, dir
);
1094 me
->me_devname
= xstrdup (thisent
+
1095 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1097 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1098 me
->me_mntroot
= NULL
;
1099 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1100 me
->me_type_malloced
= 1;
1101 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1102 ignore
= strstr (options
, "ignore");
1103 me
->me_dummy
= (ignore
1104 && (ignore
== options
|| ignore
[-1] == ',')
1105 && (ignore
[sizeof "ignore" - 1] == ','
1106 || ignore
[sizeof "ignore" - 1] == '\0'));
1107 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1109 /* Add to the linked list. */
1111 mtail
= &me
->me_next
;
1115 #endif /* MOUNTED_VMOUNT. */
1117 #ifdef MOUNTED_INTERIX_STATVFS /* Interix */
1119 DIR *dirp
= opendir ("/dev/fs");
1120 char node
[9 + NAME_MAX
];
1123 goto free_then_fail
;
1128 struct dirent entry
;
1129 struct dirent
*result
;
1131 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1132 marked obsolescent in glibc. Use readdir instead. */
1133 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1136 strcpy (node
, "/dev/fs/");
1137 strcat (node
, entry
.d_name
);
1139 if (statvfs (node
, &dev
) == 0)
1141 me
= xmalloc (sizeof *me
);
1142 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1143 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1144 me
->me_mntroot
= NULL
;
1145 me
->me_type
= xstrdup (dev
.f_fstypename
);
1146 me
->me_type_malloced
= 1;
1147 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1148 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1149 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1151 /* Add to the linked list. */
1153 mtail
= &me
->me_next
;
1158 #endif /* MOUNTED_INTERIX_STATVFS */
1164 free_then_fail
: _GL_UNUSED_LABEL
1166 int saved_errno
= errno
;
1171 me
= mount_list
->me_next
;
1172 free_mount_entry (mount_list
);
1176 errno
= saved_errno
;
1181 /* Free a mount entry as returned from read_file_system_list (). */
1183 void free_mount_entry (struct mount_entry
*me
)
1185 free (me
->me_devname
);
1186 free (me
->me_mountdir
);
1187 free (me
->me_mntroot
);
1188 if (me
->me_type_malloced
)