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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include "mountlist.h"
47 # include <sys/param.h>
50 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
52 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
53 NGROUPS is used as an array dimension in ucred.h */
54 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
57 # include <sys/mount.h>
59 # if HAVE_SYS_FS_TYPES_H
60 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
62 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
63 # define FS_TYPE(Ent) ((Ent).f_fstypename)
65 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
67 #endif /* MOUNTED_GETFSSTAT */
69 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
72 # if defined _PATH_MOUNTED /* GNU libc */
73 # define MOUNTED _PATH_MOUNTED
75 # if defined MNT_MNTTAB /* HP-UX. */
76 # define MOUNTED MNT_MNTTAB
78 # if defined MNTTABNAME /* Dynix. */
79 # define MOUNTED MNTTABNAME
84 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
85 # include <sys/mount.h>
88 #ifdef MOUNTED_GETMNT /* Ultrix. */
89 # include <sys/mount.h>
90 # include <sys/fs_types.h>
93 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
98 #ifdef MOUNTED_FREAD /* SVR2. */
102 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
104 # include <sys/fstyp.h>
105 # include <sys/statfs.h>
108 #ifdef MOUNTED_LISTMNTENT
112 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
113 # include <sys/mnttab.h>
116 #ifdef MOUNTED_VMOUNT /* AIX. */
118 # include <sys/vfs.h>
122 /* So special that it's not worth putting this in autoconf. */
123 # undef MOUNTED_FREAD_FSTYP
124 # define MOUNTED_GETMNTTBL
127 #if HAVE_SYS_MNTENT_H
128 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
129 # include <sys/mntent.h>
133 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
134 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
136 # define MNT_IGNORE(M) 0
140 # include "unlocked-io.h"
144 # define SIZE_MAX ((size_t) -1)
148 # define ME_DUMMY(Fs_name, Fs_type) \
149 (strcmp (Fs_type, "autofs") == 0 \
150 || strcmp (Fs_type, "subfs") == 0 \
152 || strcmp (Fs_type, "ignore") == 0)
156 /* A file system is `remote' if its Fs_name contains a `:'
157 or if (it is of type smbfs and its Fs_name starts with `//'). */
158 # define ME_REMOTE(Fs_name, Fs_type) \
159 (strchr (Fs_name, ':') != 0 \
160 || ((Fs_name)[0] == '/' \
161 && (Fs_name)[1] == '/' \
162 && strcmp (Fs_type, "smbfs") == 0))
165 #if MOUNTED_GETMNTINFO
167 # if ! HAVE_F_FSTYPENAME_IN_STATFS
169 fstype_to_string (short int t)
261 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
263 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
265 fsp_to_string (const struct statfs *fsp)
267 # if defined HAVE_F_FSTYPENAME_IN_STATFS
268 return (char *) (fsp->f_fstypename);
270 return fstype_to_string (fsp->f_type);
274 #endif /* MOUNTED_GETMNTINFO */
276 #ifdef MOUNTED_VMOUNT /* AIX. */
278 fstype_to_string (int t)
282 e = getvfsbytype (t);
283 if (!e || !e->vfsent_name)
286 return e->vfsent_name;
288 #endif /* MOUNTED_VMOUNT */
290 /* Return a list of the currently mounted file systems, or NULL on error.
291 Add each entry to the tail of the list so that they stay in order.
292 If NEED_FS_TYPE is true, ensure that the file system type fields in
293 the returned list are valid. Otherwise, they might not be. */
296 read_file_system_list (bool need_fs_type)
298 struct mount_entry *mount_list;
299 struct mount_entry *me;
300 struct mount_entry **mtail = &mount_list;
302 #ifdef MOUNTED_LISTMNTENT
304 struct tabmntent *mntlist, *p;
306 struct mount_entry *me;
308 /* the third and fourth arguments could be used to filter mounts,
309 but Crays doesn't seem to have any mounts that we want to
310 remove. Specifically, automount create normal NFS mounts.
313 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
315 for (p = mntlist; p; p = p->next) {
317 me = xmalloc (sizeof *me);
318 me->me_devname = xstrdup (mnt->mnt_fsname);
319 me->me_mountdir = xstrdup (mnt->mnt_dir);
320 me->me_type = xstrdup (mnt->mnt_type);
321 me->me_type_malloced = 1;
322 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
323 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
326 mtail = &me->me_next;
328 freemntlist (mntlist);
332 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
335 char *table = MOUNTED;
339 fp = setmntent (table, "r");
343 while ((mnt = getmntent (fp)))
345 me = xmalloc (sizeof *me);
346 me->me_devname = xstrdup (mnt->mnt_fsname);
347 me->me_mountdir = xstrdup (mnt->mnt_dir);
348 me->me_type = xstrdup (mnt->mnt_type);
349 me->me_type_malloced = 1;
350 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
351 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
352 devopt = strstr (mnt->mnt_opts, "dev=");
354 me->me_dev = strtoul (devopt + 4, NULL, 16);
356 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
358 /* Add to the linked list. */
360 mtail = &me->me_next;
363 if (endmntent (fp) == 0)
366 #endif /* MOUNTED_GETMNTENT1. */
368 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
373 entries = getmntinfo (&fsp, MNT_NOWAIT);
376 for (; entries-- > 0; fsp++)
378 char *fs_type = fsp_to_string (fsp);
380 me = xmalloc (sizeof *me);
381 me->me_devname = xstrdup (fsp->f_mntfromname);
382 me->me_mountdir = xstrdup (fsp->f_mntonname);
383 me->me_type = fs_type;
384 me->me_type_malloced = 0;
385 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
386 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
387 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
389 /* Add to the linked list. */
391 mtail = &me->me_next;
394 #endif /* MOUNTED_GETMNTINFO */
396 #ifdef MOUNTED_GETMNT /* Ultrix. */
403 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
406 me = xmalloc (sizeof *me);
407 me->me_devname = xstrdup (fsd.fd_req.devname);
408 me->me_mountdir = xstrdup (fsd.fd_req.path);
409 me->me_type = gt_names[fsd.fd_req.fstype];
410 me->me_type_malloced = 0;
411 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
412 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
413 me->me_dev = fsd.fd_req.dev;
415 /* Add to the linked list. */
417 mtail = &me->me_next;
422 #endif /* MOUNTED_GETMNT. */
424 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
426 /* The next_dev() and fs_stat_dev() system calls give the list of
427 all file systems, including the information returned by statvfs()
428 (fs type, total blocks, free blocks etc.), but without the mount
429 point. But on BeOS all file systems except / are mounted in the
430 rootfs, directly under /.
431 The directory name of the mount point is often, but not always,
432 identical to the volume name of the device.
433 We therefore get the list of subdirectories of /, and the list
434 of all file systems, and match the two lists. */
442 struct rootdir_entry *next;
444 struct rootdir_entry *rootdir_list;
445 struct rootdir_entry **rootdir_tail;
450 /* All volumes are mounted in the rootfs, directly under /. */
452 rootdir_tail = &rootdir_list;
453 dirp = opendir ("/");
458 while ((d = readdir (dirp)) != NULL)
463 if (strcmp (d->d_name, "..") == 0)
466 if (strcmp (d->d_name, ".") == 0)
467 name = xstrdup ("/");
470 name = xmalloc (1 + strlen (d->d_name) + 1);
472 strcpy (name + 1, d->d_name);
475 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
477 struct rootdir_entry *re = xmalloc (sizeof *re);
479 re->dev = statbuf.st_dev;
480 re->ino = statbuf.st_ino;
482 /* Add to the linked list. */
484 rootdir_tail = &re->next;
491 *rootdir_tail = NULL;
493 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
494 if (fs_stat_dev (dev, &fi) >= 0)
496 /* Note: fi.dev == dev. */
497 struct rootdir_entry *re;
499 for (re = rootdir_list; re; re = re->next)
500 if (re->dev == fi.dev && re->ino == fi.root)
503 me = xmalloc (sizeof *me);
504 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
505 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
506 me->me_type = xstrdup (fi.fsh_name);
507 me->me_type_malloced = 1;
510 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
512 /* Add to the linked list. */
514 mtail = &me->me_next;
518 while (rootdir_list != NULL)
520 struct rootdir_entry *re = rootdir_list;
521 rootdir_list = re->next;
526 #endif /* MOUNTED_FS_STAT_DEV */
528 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
532 struct statfs *stats;
534 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
537 if (SIZE_MAX / sizeof *stats <= numsys)
540 bufsize = (1 + numsys) * sizeof *stats;
541 stats = xmalloc (bufsize);
542 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
550 for (counter = 0; counter < numsys; counter++)
552 me = xmalloc (sizeof *me);
553 me->me_devname = xstrdup (stats[counter].f_mntfromname);
554 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
555 me->me_type = xstrdup (FS_TYPE (stats[counter]));
556 me->me_type_malloced = 1;
557 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
558 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
559 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
561 /* Add to the linked list. */
563 mtail = &me->me_next;
568 #endif /* MOUNTED_GETFSSTAT */
570 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
573 char *table = "/etc/mnttab";
576 fp = fopen (table, "r");
580 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
582 me = xmalloc (sizeof *me);
583 # ifdef GETFSTYP /* SVR3. */
584 me->me_devname = xstrdup (mnt.mt_dev);
586 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
587 strcpy (me->me_devname, "/dev/");
588 strcpy (me->me_devname + 5, mnt.mt_dev);
590 me->me_mountdir = xstrdup (mnt.mt_filsys);
591 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
593 me->me_type_malloced = 0;
594 # ifdef GETFSTYP /* SVR3. */
598 char typebuf[FSTYPSZ];
600 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
601 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
603 me->me_type = xstrdup (typebuf);
604 me->me_type_malloced = 1;
608 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
609 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
611 /* Add to the linked list. */
613 mtail = &me->me_next;
618 /* The last fread() call must have failed. */
619 int saved_errno = errno;
625 if (fclose (fp) == EOF)
628 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
630 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
632 struct mntent **mnttbl = getmnttbl (), **ent;
633 for (ent=mnttbl;*ent;ent++)
635 me = xmalloc (sizeof *me);
636 me->me_devname = xstrdup ( (*ent)->mt_resource);
637 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
638 me->me_type = xstrdup ((*ent)->mt_fstype);
639 me->me_type_malloced = 1;
640 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
641 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
642 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
644 /* Add to the linked list. */
646 mtail = &me->me_next;
652 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
655 char *table = MNTTAB;
660 # if defined F_RDLCK && defined F_SETLKW
661 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
662 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
663 for this file name, we should use their macro name instead.
664 (Why not just lock MNTTAB directly? We don't know.) */
666 # define MNTTAB_LOCK "/etc/.mnttab.lock"
668 lockfd = open (MNTTAB_LOCK, O_RDONLY);
672 flock.l_type = F_RDLCK;
673 flock.l_whence = SEEK_SET;
676 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
679 int saved_errno = errno;
685 else if (errno != ENOENT)
690 fp = fopen (table, "r");
695 while ((ret = getmntent (fp, &mnt)) == 0)
697 me = xmalloc (sizeof *me);
698 me->me_devname = xstrdup (mnt.mnt_special);
699 me->me_mountdir = xstrdup (mnt.mnt_mountp);
700 me->me_type = xstrdup (mnt.mnt_fstype);
701 me->me_type_malloced = 1;
702 me->me_dummy = MNT_IGNORE (&mnt) != 0;
703 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
704 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
706 /* Add to the linked list. */
708 mtail = &me->me_next;
711 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
714 if (0 <= lockfd && close (lockfd) != 0)
723 #endif /* MOUNTED_GETMNTENT2. */
725 #ifdef MOUNTED_VMOUNT /* AIX. */
728 char *entries, *thisent;
733 /* Ask how many bytes to allocate for the mounted file system info. */
734 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
736 entries = xmalloc (bufsize);
738 /* Get the list of mounted file systems. */
739 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
742 int saved_errno = errno;
748 for (i = 0, thisent = entries;
750 i++, thisent += vmp->vmt_length)
752 char *options, *ignore;
754 vmp = (struct vmount *) thisent;
755 me = xmalloc (sizeof *me);
756 if (vmp->vmt_flags & MNT_REMOTE)
761 /* Prepend the remote pathname. */
762 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
763 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
764 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
765 strcpy (me->me_devname, host);
766 strcat (me->me_devname, ":");
767 strcat (me->me_devname, path);
772 me->me_devname = xstrdup (thisent +
773 vmp->vmt_data[VMT_OBJECT].vmt_off);
775 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
776 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
777 me->me_type_malloced = 1;
778 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
779 ignore = strstr (options, "ignore");
780 me->me_dummy = (ignore
781 && (ignore == options || ignore[-1] == ',')
782 && (ignore[sizeof "ignore" - 1] == ','
783 || ignore[sizeof "ignore" - 1] == '\0'));
784 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
786 /* Add to the linked list. */
788 mtail = &me->me_next;
792 #endif /* MOUNTED_VMOUNT. */
800 int saved_errno = errno;
805 me = mount_list->me_next;
806 free (mount_list->me_devname);
807 free (mount_list->me_mountdir);
808 if (mount_list->me_type_malloced)
809 free (mount_list->me_type);