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 and Darwin1.3.x */
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 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
67 # include <sys/types.h>
69 # if defined _PATH_MOUNTED /* GNU libc */
70 # define MOUNTED _PATH_MOUNTED
72 # if defined MNT_MNTTAB /* HP-UX. */
73 # define MOUNTED MNT_MNTTAB
75 # if defined MNTTABNAME /* Dynix. */
76 # define MOUNTED MNTTABNAME
81 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
82 # include <sys/mount.h>
85 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
86 # include <sys/statvfs.h>
89 #ifdef MOUNTED_GETMNT /* Ultrix. */
90 # include <sys/mount.h>
91 # include <sys/fs_types.h>
94 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
99 #ifdef MOUNTED_FREAD /* SVR2. */
103 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
105 # include <sys/fstyp.h>
106 # include <sys/statfs.h>
109 #ifdef MOUNTED_LISTMNTENT
113 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
114 # include <sys/mnttab.h>
117 #ifdef MOUNTED_VMOUNT /* AIX. */
119 # include <sys/vfs.h>
122 #ifdef MOUNTED_INTERIX_STATVFS /* Interix. */
123 # include <sys/statvfs.h>
128 /* So special that it's not worth putting this in autoconf. */
129 # undef MOUNTED_FREAD_FSTYP
130 # define MOUNTED_GETMNTTBL
133 #if HAVE_SYS_MNTENT_H
134 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
135 # include <sys/mntent.h>
138 #ifndef HAVE_HASMNTOPT
139 # define hasmntopt(mnt, opt) ((char *) 0)
144 # if defined __sun && defined __SVR4
145 /* Solaris defines hasmntopt(struct mnttab *, char *)
146 while it is otherwise hasmntopt(struct mnttab *, const char *). */
147 # define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
149 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
152 # define MNT_IGNORE(M) 0
156 # include "unlocked-io.h"
159 /* The results of opendir() in this file are not used with dirfd and fchdir,
160 therefore save some unnecessary work in fchdir.c. */
161 #ifdef GNULIB_defined_opendir
164 #ifdef GNULIB_defined_closedir
168 #define ME_DUMMY_0(Fs_name, Fs_type) \
169 (strcmp (Fs_type, "autofs") == 0 \
170 || strcmp (Fs_type, "proc") == 0 \
171 || strcmp (Fs_type, "subfs") == 0 \
172 /* for Linux 2.6/3.x */ \
173 || strcmp (Fs_type, "debugfs") == 0 \
174 || strcmp (Fs_type, "devpts") == 0 \
175 || strcmp (Fs_type, "fusectl") == 0 \
176 || strcmp (Fs_type, "mqueue") == 0 \
177 || strcmp (Fs_type, "rpc_pipefs") == 0 \
178 || strcmp (Fs_type, "sysfs") == 0 \
179 /* FreeBSD, Linux 2.4 */ \
180 || strcmp (Fs_type, "devfs") == 0 \
181 /* for NetBSD 3.0 */ \
182 || strcmp (Fs_type, "kernfs") == 0 \
184 || strcmp (Fs_type, "ignore") == 0)
186 /* Historically, we have marked as "dummy" any file system of type "none",
187 but now that programs like du need to know about bind-mounted directories,
188 we grant an exception to any with "bind" in its list of mount options.
189 I.e., those are *not* dummy entries. */
190 #ifdef MOUNTED_GETMNTENT1
191 # define ME_DUMMY(Fs_name, Fs_type, Bind) \
192 (ME_DUMMY_0 (Fs_name, Fs_type) \
193 || (strcmp (Fs_type, "none") == 0 && !Bind))
195 # define ME_DUMMY(Fs_name, Fs_type) \
196 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
200 # include <windows.h>
201 # define ME_REMOTE me_remote
202 /* All cygwin mount points include ':' or start with '//'; so it
203 requires a native Windows call to determine remote disks. */
205 me_remote (char const *fs_name
, char const *fs_type _GL_UNUSED
)
207 if (fs_name
[0] && fs_name
[1] == ':')
210 sprintf (drive
, "%c:\\", fs_name
[0]);
211 switch (GetDriveType (drive
))
213 case DRIVE_REMOVABLE
:
225 /* A file system is "remote" if its Fs_name contains a ':'
226 or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
227 or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
228 # define ME_REMOTE(Fs_name, Fs_type) \
229 (strchr (Fs_name, ':') != NULL \
230 || ((Fs_name)[0] == '/' \
231 && (Fs_name)[1] == '/' \
232 && (strcmp (Fs_type, "smbfs") == 0 \
233 || strcmp (Fs_type, "cifs") == 0)) \
234 || (strcmp("-hosts", Fs_name) == 0))
237 #if MOUNTED_GETMNTINFO
239 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
241 fstype_to_string (short int t
)
336 fsp_to_string (const struct statfs
*fsp
)
338 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
339 return (char *) (fsp
->f_fstypename
);
341 return fstype_to_string (fsp
->f_type
);
345 #endif /* MOUNTED_GETMNTINFO */
347 #ifdef MOUNTED_VMOUNT /* AIX. */
349 fstype_to_string (int t
)
353 e
= getvfsbytype (t
);
354 if (!e
|| !e
->vfsent_name
)
357 return e
->vfsent_name
;
359 #endif /* MOUNTED_VMOUNT */
362 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
364 /* Return the device number from MOUNT_OPTIONS, if possible.
365 Otherwise return (dev_t) -1. */
367 dev_from_mount_options (char const *mount_options
)
369 /* GNU/Linux allows file system implementations to define their own
370 meaning for "dev=" mount options, so don't trust the meaning
374 static char const dev_pattern
[] = ",dev=";
375 char const *devopt
= strstr (mount_options
, dev_pattern
);
379 char const *optval
= devopt
+ sizeof dev_pattern
- 1;
381 unsigned long int dev
;
383 dev
= strtoul (optval
, &optvalend
, 16);
384 if (optval
!= optvalend
385 && (*optvalend
== '\0' || *optvalend
== ',')
386 && ! (dev
== ULONG_MAX
&& errno
== ERANGE
)
387 && dev
== (dev_t
) dev
)
392 (void) mount_options
;
398 #if defined MOUNTED_GETMNTENT1 && defined __linux__
400 /* Unescape the paths in mount tables.
401 STR is updated in place. */
404 unescape_tab (char *str
)
407 size_t len
= strlen (str
) + 1;
408 for (i
= 0; i
< len
; i
++)
410 if (str
[i
] == '\\' && (i
+ 4 < len
)
411 && str
[i
+ 1] >= '0' && str
[i
+ 1] <= '3'
412 && str
[i
+ 2] >= '0' && str
[i
+ 2] <= '7'
413 && str
[i
+ 3] >= '0' && str
[i
+ 3] <= '7')
415 str
[j
++] = (str
[i
+ 1] - '0') * 64 +
416 (str
[i
+ 2] - '0') * 8 +
426 /* Return a list of the currently mounted file systems, or NULL on error.
427 Add each entry to the tail of the list so that they stay in order.
428 If NEED_FS_TYPE is true, ensure that the file system type fields in
429 the returned list are valid. Otherwise, they might not be. */
432 read_file_system_list (bool need_fs_type
)
434 struct mount_entry
*mount_list
;
435 struct mount_entry
*me
;
436 struct mount_entry
**mtail
= &mount_list
;
439 #ifdef MOUNTED_LISTMNTENT
441 struct tabmntent
*mntlist
, *p
;
444 /* the third and fourth arguments could be used to filter mounts,
445 but Crays doesn't seem to have any mounts that we want to
446 remove. Specifically, automount create normal NFS mounts.
449 if (listmntent (&mntlist
, KMTAB
, NULL
, NULL
) < 0)
451 for (p
= mntlist
; p
; p
= p
->next
)
454 me
= xmalloc (sizeof *me
);
455 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
456 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
457 me
->me_mntroot
= NULL
;
458 me
->me_type
= xstrdup (mnt
->mnt_type
);
459 me
->me_type_malloced
= 1;
460 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
461 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
464 mtail
= &me
->me_next
;
466 freemntlist (mntlist
);
470 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
475 /* Try parsing mountinfo first, as that make device IDs available.
476 Note we could use libmount routines to simplify this parsing a little
477 (and that code is in previous versions of this function), however
478 libmount depends on libselinux which pulls in many dependencies. */
479 char const *mountinfo
= "/proc/self/mountinfo";
480 fp
= fopen (mountinfo
, "r");
486 while (getline (&line
, &buf_size
, fp
) != -1)
488 unsigned int devmaj
, devmin
;
489 int target_s
, target_e
, type_s
, type_e
;
490 int source_s
, source_e
, mntroot_s
, mntroot_e
;
495 rc
= sscanf(line
, "%*u " /* id - discarded */
496 "%*u " /* parent - discarded */
497 "%u:%u " /* dev major:minor */
498 "%n%*s%n " /* mountroot */
499 "%n%*s%n" /* target, start and end */
500 "%c", /* more data... */
502 &mntroot_s
, &mntroot_e
,
503 &target_s
, &target_e
,
506 if (rc
!= 3 && rc
!= 7) /* 7 if %n included in count. */
509 /* skip optional fields, terminated by " - " */
510 dash
= strstr (line
+ target_e
, " - ");
514 rc
= sscanf(dash
, " - "
515 "%n%*s%n " /* FS type, start and end */
516 "%n%*s%n " /* source, start and end */
517 "%c", /* more data... */
519 &source_s
, &source_e
,
521 if (rc
!= 1 && rc
!= 5) /* 5 if %n included in count. */
524 /* manipulate the sub-strings in place. */
525 line
[mntroot_e
] = '\0';
526 line
[target_e
] = '\0';
528 dash
[source_e
] = '\0';
529 unescape_tab (dash
+ source_s
);
530 unescape_tab (line
+ target_s
);
531 unescape_tab (line
+ mntroot_s
);
533 me
= xmalloc (sizeof *me
);
535 me
->me_devname
= xstrdup (dash
+ source_s
);
536 me
->me_mountdir
= xstrdup (line
+ target_s
);
537 me
->me_mntroot
= xstrdup (line
+ mntroot_s
);
538 me
->me_type
= xstrdup (dash
+ type_s
);
539 me
->me_type_malloced
= 1;
540 me
->me_dev
= makedev (devmaj
, devmin
);
541 /* we pass "false" for the "Bind" option as that's only
542 significant when the Fs_type is "none" which will not be
543 the case when parsing "/proc/self/mountinfo", and only
544 applies for static /etc/mtab files. */
545 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, false);
546 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
548 /* Add to the linked list. */
550 mtail
= &me
->me_next
;
557 int saved_errno
= errno
;
563 if (fclose (fp
) == EOF
)
566 else /* fallback to /proc/self/mounts (/etc/mtab). */
567 #endif /* __linux __ */
570 char const *table
= MOUNTED
;
572 fp
= setmntent (table
, "r");
576 while ((mnt
= getmntent (fp
)))
578 bool bind
= hasmntopt (mnt
, "bind");
580 me
= xmalloc (sizeof *me
);
581 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
582 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
583 me
->me_mntroot
= NULL
;
584 me
->me_type
= xstrdup (mnt
->mnt_type
);
585 me
->me_type_malloced
= 1;
586 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
, bind
);
587 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
588 me
->me_dev
= dev_from_mount_options (mnt
->mnt_opts
);
590 /* Add to the linked list. */
592 mtail
= &me
->me_next
;
595 if (endmntent (fp
) == 0)
599 #endif /* MOUNTED_GETMNTENT1. */
601 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
606 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
609 for (; entries
-- > 0; fsp
++)
611 char *fs_type
= fsp_to_string (fsp
);
613 me
= xmalloc (sizeof *me
);
614 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
615 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
616 me
->me_mntroot
= NULL
;
617 me
->me_type
= fs_type
;
618 me
->me_type_malloced
= 0;
619 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
620 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
621 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
623 /* Add to the linked list. */
625 mtail
= &me
->me_next
;
628 #endif /* MOUNTED_GETMNTINFO */
630 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
635 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
638 for (; entries
-- > 0; fsp
++)
640 me
= xmalloc (sizeof *me
);
641 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
642 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
643 me
->me_mntroot
= NULL
;
644 me
->me_type
= xstrdup (fsp
->f_fstypename
);
645 me
->me_type_malloced
= 1;
646 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
647 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
648 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
650 /* Add to the linked list. */
652 mtail
= &me
->me_next
;
655 #endif /* MOUNTED_GETMNTINFO2 */
657 #ifdef MOUNTED_GETMNT /* Ultrix. */
664 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
667 me
= xmalloc (sizeof *me
);
668 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
669 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
670 me
->me_mntroot
= NULL
;
671 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
672 me
->me_type_malloced
= 0;
673 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
674 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
675 me
->me_dev
= fsd
.fd_req
.dev
;
677 /* Add to the linked list. */
679 mtail
= &me
->me_next
;
684 #endif /* MOUNTED_GETMNT. */
686 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
688 /* The next_dev() and fs_stat_dev() system calls give the list of
689 all file systems, including the information returned by statvfs()
690 (fs type, total blocks, free blocks etc.), but without the mount
691 point. But on BeOS all file systems except / are mounted in the
692 rootfs, directly under /.
693 The directory name of the mount point is often, but not always,
694 identical to the volume name of the device.
695 We therefore get the list of subdirectories of /, and the list
696 of all file systems, and match the two lists. */
704 struct rootdir_entry
*next
;
706 struct rootdir_entry
*rootdir_list
;
707 struct rootdir_entry
**rootdir_tail
;
712 /* All volumes are mounted in the rootfs, directly under /. */
714 rootdir_tail
= &rootdir_list
;
715 dirp
= opendir ("/");
720 while ((d
= readdir (dirp
)) != NULL
)
725 if (strcmp (d
->d_name
, "..") == 0)
728 if (strcmp (d
->d_name
, ".") == 0)
729 name
= xstrdup ("/");
732 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
734 strcpy (name
+ 1, d
->d_name
);
737 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
739 struct rootdir_entry
*re
= xmalloc (sizeof *re
);
741 re
->dev
= statbuf
.st_dev
;
742 re
->ino
= statbuf
.st_ino
;
744 /* Add to the linked list. */
746 rootdir_tail
= &re
->next
;
753 *rootdir_tail
= NULL
;
755 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
756 if (fs_stat_dev (dev
, &fi
) >= 0)
758 /* Note: fi.dev == dev. */
759 struct rootdir_entry
*re
;
761 for (re
= rootdir_list
; re
; re
= re
->next
)
762 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
765 me
= xmalloc (sizeof *me
);
766 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0'
767 ? fi
.device_name
: fi
.fsh_name
);
768 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
769 me
->me_mntroot
= NULL
;
770 me
->me_type
= xstrdup (fi
.fsh_name
);
771 me
->me_type_malloced
= 1;
774 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
776 /* Add to the linked list. */
778 mtail
= &me
->me_next
;
782 while (rootdir_list
!= NULL
)
784 struct rootdir_entry
*re
= rootdir_list
;
785 rootdir_list
= re
->next
;
790 #endif /* MOUNTED_FS_STAT_DEV */
792 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
796 struct statfs
*stats
;
798 numsys
= getfsstat (NULL
, 0L, MNT_NOWAIT
);
801 if (SIZE_MAX
/ sizeof *stats
<= numsys
)
804 bufsize
= (1 + numsys
) * sizeof *stats
;
805 stats
= xmalloc (bufsize
);
806 numsys
= getfsstat (stats
, bufsize
, MNT_NOWAIT
);
814 for (counter
= 0; counter
< numsys
; counter
++)
816 me
= xmalloc (sizeof *me
);
817 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
818 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
819 me
->me_mntroot
= NULL
;
820 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
821 me
->me_type_malloced
= 1;
822 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
823 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
824 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
826 /* Add to the linked list. */
828 mtail
= &me
->me_next
;
833 #endif /* MOUNTED_GETFSSTAT */
835 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
838 char *table
= "/etc/mnttab";
841 fp
= fopen (table
, "r");
845 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
847 me
= xmalloc (sizeof *me
);
848 # ifdef GETFSTYP /* SVR3. */
849 me
->me_devname
= xstrdup (mnt
.mt_dev
);
851 me
->me_devname
= xmalloc (strlen (mnt
.mt_dev
) + 6);
852 strcpy (me
->me_devname
, "/dev/");
853 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
855 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
856 me
->me_mntroot
= NULL
;
857 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
859 me
->me_type_malloced
= 0;
860 # ifdef GETFSTYP /* SVR3. */
864 char typebuf
[FSTYPSZ
];
866 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
867 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
869 me
->me_type
= xstrdup (typebuf
);
870 me
->me_type_malloced
= 1;
874 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
875 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
877 /* Add to the linked list. */
879 mtail
= &me
->me_next
;
884 /* The last fread() call must have failed. */
885 int saved_errno
= errno
;
891 if (fclose (fp
) == EOF
)
894 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
896 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
898 struct mntent
**mnttbl
= getmnttbl (), **ent
;
899 for (ent
= mnttbl
; *ent
; ent
++)
901 me
= xmalloc (sizeof *me
);
902 me
->me_devname
= xstrdup ((*ent
)->mt_resource
);
903 me
->me_mountdir
= xstrdup ((*ent
)->mt_directory
);
904 me
->me_mntroot
= NULL
;
905 me
->me_type
= xstrdup ((*ent
)->mt_fstype
);
906 me
->me_type_malloced
= 1;
907 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
908 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
909 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
911 /* Add to the linked list. */
913 mtail
= &me
->me_next
;
919 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
922 char *table
= MNTTAB
;
927 # if defined F_RDLCK && defined F_SETLKW
928 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
929 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
930 for this file name, we should use their macro name instead.
931 (Why not just lock MNTTAB directly? We don't know.) */
933 # define MNTTAB_LOCK "/etc/.mnttab.lock"
935 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
939 flock
.l_type
= F_RDLCK
;
940 flock
.l_whence
= SEEK_SET
;
943 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
946 int saved_errno
= errno
;
952 else if (errno
!= ENOENT
)
957 fp
= fopen (table
, "r");
962 while ((ret
= getmntent (fp
, &mnt
)) == 0)
964 me
= xmalloc (sizeof *me
);
965 me
->me_devname
= xstrdup (mnt
.mnt_special
);
966 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
967 me
->me_mntroot
= NULL
;
968 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
969 me
->me_type_malloced
= 1;
970 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
971 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
972 me
->me_dev
= dev_from_mount_options (mnt
.mnt_mntopts
);
974 /* Add to the linked list. */
976 mtail
= &me
->me_next
;
979 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
982 if (0 <= lockfd
&& close (lockfd
) != 0)
991 #endif /* MOUNTED_GETMNTENT2. */
993 #ifdef MOUNTED_VMOUNT /* AIX. */
1002 /* Ask how many bytes to allocate for the mounted file system info. */
1004 if (mntctl (MCTL_QUERY
, sizeof bufsize
, entries
) != 0)
1006 entries
= xmalloc (bufsize
);
1008 /* Get the list of mounted file systems. */
1009 n_entries
= mntctl (MCTL_QUERY
, bufsize
, entries
);
1012 int saved_errno
= errno
;
1014 errno
= saved_errno
;
1018 for (i
= 0, thisent
= entries
;
1020 i
++, thisent
+= vmp
->vmt_length
)
1022 char *options
, *ignore
;
1024 vmp
= (struct vmount
*) thisent
;
1025 me
= xmalloc (sizeof *me
);
1026 if (vmp
->vmt_flags
& MNT_REMOTE
)
1031 /* Prepend the remote dirname. */
1032 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
1033 dir
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
1034 me
->me_devname
= xmalloc (strlen (host
) + strlen (dir
) + 2);
1035 strcpy (me
->me_devname
, host
);
1036 strcat (me
->me_devname
, ":");
1037 strcat (me
->me_devname
, dir
);
1042 me
->me_devname
= xstrdup (thisent
+
1043 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
1045 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
1046 me
->me_mntroot
= NULL
;
1047 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
1048 me
->me_type_malloced
= 1;
1049 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
1050 ignore
= strstr (options
, "ignore");
1051 me
->me_dummy
= (ignore
1052 && (ignore
== options
|| ignore
[-1] == ',')
1053 && (ignore
[sizeof "ignore" - 1] == ','
1054 || ignore
[sizeof "ignore" - 1] == '\0'));
1055 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
1057 /* Add to the linked list. */
1059 mtail
= &me
->me_next
;
1063 #endif /* MOUNTED_VMOUNT. */
1065 #ifdef MOUNTED_INTERIX_STATVFS
1067 DIR *dirp
= opendir ("/dev/fs");
1068 char node
[9 + NAME_MAX
];
1071 goto free_then_fail
;
1076 struct dirent entry
;
1077 struct dirent
*result
;
1079 /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1080 marked obsolescent in glibc. Use readdir instead. */
1081 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
1084 strcpy (node
, "/dev/fs/");
1085 strcat (node
, entry
.d_name
);
1087 if (statvfs (node
, &dev
) == 0)
1089 me
= xmalloc (sizeof *me
);
1090 me
->me_devname
= xstrdup (dev
.f_mntfromname
);
1091 me
->me_mountdir
= xstrdup (dev
.f_mntonname
);
1092 me
->me_mntroot
= NULL
;
1093 me
->me_type
= xstrdup (dev
.f_fstypename
);
1094 me
->me_type_malloced
= 1;
1095 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
1096 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
1097 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
1099 /* Add to the linked list. */
1101 mtail
= &me
->me_next
;
1106 #endif /* MOUNTED_INTERIX_STATVFS */
1112 free_then_fail
: _GL_UNUSED_LABEL
1114 int saved_errno
= errno
;
1119 me
= mount_list
->me_next
;
1120 free_mount_entry (mount_list
);
1124 errno
= saved_errno
;
1129 /* Free a mount entry as returned from read_file_system_list (). */
1131 void free_mount_entry (struct mount_entry
*me
)
1133 free (me
->me_devname
);
1134 free (me
->me_mountdir
);
1135 free (me
->me_mntroot
);
1136 if (me
->me_type_malloced
)