1 /* mountlist.c -- return a list of mounted file systems
3 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include "mountlist.h"
43 # include <sys/param.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. */
68 # if defined _PATH_MOUNTED /* GNU libc */
69 # define MOUNTED _PATH_MOUNTED
71 # if defined MNT_MNTTAB /* HP-UX. */
72 # define MOUNTED MNT_MNTTAB
74 # if defined MNTTABNAME /* Dynix. */
75 # define MOUNTED MNTTABNAME
80 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
81 # include <sys/mount.h>
84 #ifdef MOUNTED_GETMNT /* Ultrix. */
85 # include <sys/mount.h>
86 # include <sys/fs_types.h>
89 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
94 #ifdef MOUNTED_FREAD /* SVR2. */
98 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
100 # include <sys/fstyp.h>
101 # include <sys/statfs.h>
104 #ifdef MOUNTED_LISTMNTENT
108 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
109 # include <sys/mnttab.h>
112 #ifdef MOUNTED_VMOUNT /* AIX. */
114 # include <sys/vfs.h>
118 /* So special that it's not worth putting this in autoconf. */
119 # undef MOUNTED_FREAD_FSTYP
120 # define MOUNTED_GETMNTTBL
123 #if HAVE_SYS_MNTENT_H
124 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
125 # include <sys/mntent.h>
129 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
130 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
132 # define MNT_IGNORE(M) 0
136 # include "unlocked-io.h"
140 # define SIZE_MAX ((size_t) -1)
144 # define ME_DUMMY(Fs_name, Fs_type) \
145 (strcmp (Fs_type, "autofs") == 0 \
146 || strcmp (Fs_type, "subfs") == 0 \
148 || strcmp (Fs_type, "ignore") == 0)
152 /* A file system is `remote' if its Fs_name contains a `:'
153 or if (it is of type smbfs and its Fs_name starts with `//'). */
154 # define ME_REMOTE(Fs_name, Fs_type) \
155 (strchr (Fs_name, ':') != 0 \
156 || ((Fs_name)[0] == '/' \
157 && (Fs_name)[1] == '/' \
158 && strcmp (Fs_type, "smbfs") == 0))
161 #if MOUNTED_GETMNTINFO
163 # if ! HAVE_F_FSTYPENAME_IN_STATFS
165 fstype_to_string (short int t)
257 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
259 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
261 fsp_to_string (const struct statfs *fsp)
263 # if defined HAVE_F_FSTYPENAME_IN_STATFS
264 return (char *) (fsp->f_fstypename);
266 return fstype_to_string (fsp->f_type);
270 #endif /* MOUNTED_GETMNTINFO */
272 #ifdef MOUNTED_VMOUNT /* AIX. */
274 fstype_to_string (int t)
278 e = getvfsbytype (t);
279 if (!e || !e->vfsent_name)
282 return e->vfsent_name;
284 #endif /* MOUNTED_VMOUNT */
286 /* Return a list of the currently mounted file systems, or NULL on error.
287 Add each entry to the tail of the list so that they stay in order.
288 If NEED_FS_TYPE is true, ensure that the file system type fields in
289 the returned list are valid. Otherwise, they might not be. */
292 read_file_system_list (bool need_fs_type)
294 struct mount_entry *mount_list;
295 struct mount_entry *me;
296 struct mount_entry **mtail = &mount_list;
298 #ifdef MOUNTED_LISTMNTENT
300 struct tabmntent *mntlist, *p;
302 struct mount_entry *me;
304 /* the third and fourth arguments could be used to filter mounts,
305 but Crays doesn't seem to have any mounts that we want to
306 remove. Specifically, automount create normal NFS mounts.
309 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
311 for (p = mntlist; p; p = p->next) {
313 me = xmalloc (sizeof *me);
314 me->me_devname = xstrdup (mnt->mnt_fsname);
315 me->me_mountdir = xstrdup (mnt->mnt_dir);
316 me->me_type = xstrdup (mnt->mnt_type);
317 me->me_type_malloced = 1;
318 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
319 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
322 mtail = &me->me_next;
324 freemntlist (mntlist);
328 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
331 char *table = MOUNTED;
335 fp = setmntent (table, "r");
339 while ((mnt = getmntent (fp)))
341 me = xmalloc (sizeof *me);
342 me->me_devname = xstrdup (mnt->mnt_fsname);
343 me->me_mountdir = xstrdup (mnt->mnt_dir);
344 me->me_type = xstrdup (mnt->mnt_type);
345 me->me_type_malloced = 1;
346 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
347 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
348 devopt = strstr (mnt->mnt_opts, "dev=");
350 me->me_dev = strtoul (devopt + 4, NULL, 16);
352 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
354 /* Add to the linked list. */
356 mtail = &me->me_next;
359 if (endmntent (fp) == 0)
362 #endif /* MOUNTED_GETMNTENT1. */
364 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
369 entries = getmntinfo (&fsp, MNT_NOWAIT);
372 for (; entries-- > 0; fsp++)
374 char *fs_type = fsp_to_string (fsp);
376 me = xmalloc (sizeof *me);
377 me->me_devname = xstrdup (fsp->f_mntfromname);
378 me->me_mountdir = xstrdup (fsp->f_mntonname);
379 me->me_type = fs_type;
380 me->me_type_malloced = 0;
381 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
382 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
383 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
385 /* Add to the linked list. */
387 mtail = &me->me_next;
390 #endif /* MOUNTED_GETMNTINFO */
392 #ifdef MOUNTED_GETMNT /* Ultrix. */
399 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
402 me = xmalloc (sizeof *me);
403 me->me_devname = xstrdup (fsd.fd_req.devname);
404 me->me_mountdir = xstrdup (fsd.fd_req.path);
405 me->me_type = gt_names[fsd.fd_req.fstype];
406 me->me_type_malloced = 0;
407 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
408 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
409 me->me_dev = fsd.fd_req.dev;
411 /* Add to the linked list. */
413 mtail = &me->me_next;
418 #endif /* MOUNTED_GETMNT. */
420 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
422 /* The next_dev() and fs_stat_dev() system calls give the list of
423 all file systems, including the information returned by statvfs()
424 (fs type, total blocks, free blocks etc.), but without the mount
425 point. But on BeOS all file systems except / are mounted in the
426 rootfs, directly under /.
427 The directory name of the mount point is often, but not always,
428 identical to the volume name of the device.
429 We therefore get the list of subdirectories of /, and the list
430 of all file systems, and match the two lists. */
438 struct rootdir_entry *next;
440 struct rootdir_entry *rootdir_list;
441 struct rootdir_entry **rootdir_tail;
446 /* All volumes are mounted in the rootfs, directly under /. */
448 rootdir_tail = &rootdir_list;
449 dirp = opendir ("/");
454 while ((d = readdir (dirp)) != NULL)
459 if (strcmp (d->d_name, "..") == 0)
462 if (strcmp (d->d_name, ".") == 0)
463 name = xstrdup ("/");
466 name = xmalloc (1 + strlen (d->d_name) + 1);
468 strcpy (name + 1, d->d_name);
471 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
473 struct rootdir_entry *re = xmalloc (sizeof *re);
475 re->dev = statbuf.st_dev;
476 re->ino = statbuf.st_ino;
478 /* Add to the linked list. */
480 rootdir_tail = &re->next;
487 *rootdir_tail = NULL;
489 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
490 if (fs_stat_dev (dev, &fi) >= 0)
492 /* Note: fi.dev == dev. */
493 struct rootdir_entry *re;
495 for (re = rootdir_list; re; re = re->next)
496 if (re->dev == fi.dev && re->ino == fi.root)
499 me = xmalloc (sizeof *me);
500 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
501 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
502 me->me_type = xstrdup (fi.fsh_name);
503 me->me_type_malloced = 1;
506 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
508 /* Add to the linked list. */
510 mtail = &me->me_next;
514 while (rootdir_list != NULL)
516 struct rootdir_entry *re = rootdir_list;
517 rootdir_list = re->next;
522 #endif /* MOUNTED_FS_STAT_DEV */
524 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
528 struct statfs *stats;
530 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
533 if (SIZE_MAX / sizeof *stats <= numsys)
536 bufsize = (1 + numsys) * sizeof *stats;
537 stats = xmalloc (bufsize);
538 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
546 for (counter = 0; counter < numsys; counter++)
548 me = xmalloc (sizeof *me);
549 me->me_devname = xstrdup (stats[counter].f_mntfromname);
550 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
551 me->me_type = xstrdup (FS_TYPE (stats[counter]));
552 me->me_type_malloced = 1;
553 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
554 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
555 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
557 /* Add to the linked list. */
559 mtail = &me->me_next;
564 #endif /* MOUNTED_GETFSSTAT */
566 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
569 char *table = "/etc/mnttab";
572 fp = fopen (table, "r");
576 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
578 me = xmalloc (sizeof *me);
579 # ifdef GETFSTYP /* SVR3. */
580 me->me_devname = xstrdup (mnt.mt_dev);
582 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
583 strcpy (me->me_devname, "/dev/");
584 strcpy (me->me_devname + 5, mnt.mt_dev);
586 me->me_mountdir = xstrdup (mnt.mt_filsys);
587 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
589 me->me_type_malloced = 0;
590 # ifdef GETFSTYP /* SVR3. */
594 char typebuf[FSTYPSZ];
596 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
597 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
599 me->me_type = xstrdup (typebuf);
600 me->me_type_malloced = 1;
604 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
605 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
607 /* Add to the linked list. */
609 mtail = &me->me_next;
614 /* The last fread() call must have failed. */
615 int saved_errno = errno;
621 if (fclose (fp) == EOF)
624 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
626 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
628 struct mntent **mnttbl = getmnttbl (), **ent;
629 for (ent=mnttbl;*ent;ent++)
631 me = xmalloc (sizeof *me);
632 me->me_devname = xstrdup ( (*ent)->mt_resource);
633 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
634 me->me_type = xstrdup ((*ent)->mt_fstype);
635 me->me_type_malloced = 1;
636 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
637 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
638 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
640 /* Add to the linked list. */
642 mtail = &me->me_next;
648 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
651 char *table = MNTTAB;
656 # if defined F_RDLCK && defined F_SETLKW
657 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
658 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
659 for this file name, we should use their macro name instead.
660 (Why not just lock MNTTAB directly? We don't know.) */
662 # define MNTTAB_LOCK "/etc/.mnttab.lock"
664 lockfd = open (MNTTAB_LOCK, O_RDONLY);
668 flock.l_type = F_RDLCK;
669 flock.l_whence = SEEK_SET;
672 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
675 int saved_errno = errno;
681 else if (errno != ENOENT)
686 fp = fopen (table, "r");
691 while ((ret = getmntent (fp, &mnt)) == 0)
693 me = xmalloc (sizeof *me);
694 me->me_devname = xstrdup (mnt.mnt_special);
695 me->me_mountdir = xstrdup (mnt.mnt_mountp);
696 me->me_type = xstrdup (mnt.mnt_fstype);
697 me->me_type_malloced = 1;
698 me->me_dummy = MNT_IGNORE (&mnt) != 0;
699 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
700 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
702 /* Add to the linked list. */
704 mtail = &me->me_next;
707 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
710 if (0 <= lockfd && close (lockfd) != 0)
719 #endif /* MOUNTED_GETMNTENT2. */
721 #ifdef MOUNTED_VMOUNT /* AIX. */
724 char *entries, *thisent;
729 /* Ask how many bytes to allocate for the mounted file system info. */
730 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
732 entries = xmalloc (bufsize);
734 /* Get the list of mounted file systems. */
735 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
738 int saved_errno = errno;
744 for (i = 0, thisent = entries;
746 i++, thisent += vmp->vmt_length)
748 char *options, *ignore;
750 vmp = (struct vmount *) thisent;
751 me = xmalloc (sizeof *me);
752 if (vmp->vmt_flags & MNT_REMOTE)
757 /* Prepend the remote dirname. */
758 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
759 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
760 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
761 strcpy (me->me_devname, host);
762 strcat (me->me_devname, ":");
763 strcat (me->me_devname, dir);
768 me->me_devname = xstrdup (thisent +
769 vmp->vmt_data[VMT_OBJECT].vmt_off);
771 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
772 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
773 me->me_type_malloced = 1;
774 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
775 ignore = strstr (options, "ignore");
776 me->me_dummy = (ignore
777 && (ignore == options || ignore[-1] == ',')
778 && (ignore[sizeof "ignore" - 1] == ','
779 || ignore[sizeof "ignore" - 1] == '\0'));
780 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
782 /* Add to the linked list. */
784 mtail = &me->me_next;
788 #endif /* MOUNTED_VMOUNT. */
796 int saved_errno = errno;
801 me = mount_list->me_next;
802 free (mount_list->me_devname);
803 free (mount_list->me_mountdir);
804 if (mount_list->me_type_malloced)
805 free (mount_list->me_type);