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"
45 # include <sys/param.h>
48 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
50 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
51 NGROUPS is used as an array dimension in ucred.h */
52 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
55 # include <sys/mount.h>
57 # if HAVE_SYS_FS_TYPES_H
58 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
60 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
61 # define FS_TYPE(Ent) ((Ent).f_fstypename)
63 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
65 #endif /* MOUNTED_GETFSSTAT */
67 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
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 /* 4.4BSD. */
83 # include <sys/mount.h>
86 #ifdef MOUNTED_GETMNT /* Ultrix. */
87 # include <sys/mount.h>
88 # include <sys/fs_types.h>
91 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
96 #ifdef MOUNTED_FREAD /* SVR2. */
100 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
102 # include <sys/fstyp.h>
103 # include <sys/statfs.h>
106 #ifdef MOUNTED_LISTMNTENT
110 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
111 # include <sys/mnttab.h>
114 #ifdef MOUNTED_VMOUNT /* AIX. */
116 # include <sys/vfs.h>
120 /* So special that it's not worth putting this in autoconf. */
121 # undef MOUNTED_FREAD_FSTYP
122 # define MOUNTED_GETMNTTBL
125 #if HAVE_SYS_MNTENT_H
126 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
127 # include <sys/mntent.h>
131 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
132 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
134 # define MNT_IGNORE(M) 0
138 # include "unlocked-io.h"
142 # define SIZE_MAX ((size_t) -1)
146 # define ME_DUMMY(Fs_name, Fs_type) \
147 (strcmp (Fs_type, "autofs") == 0 \
148 || strcmp (Fs_type, "subfs") == 0 \
150 || strcmp (Fs_type, "ignore") == 0)
154 /* A file system is `remote' if its Fs_name contains a `:'
155 or if (it is of type smbfs and its Fs_name starts with `//'). */
156 # define ME_REMOTE(Fs_name, Fs_type) \
157 (strchr (Fs_name, ':') != 0 \
158 || ((Fs_name)[0] == '/' \
159 && (Fs_name)[1] == '/' \
160 && strcmp (Fs_type, "smbfs") == 0))
163 #if MOUNTED_GETMNTINFO
165 # if ! HAVE_F_FSTYPENAME_IN_STATFS
167 fstype_to_string (short int t)
259 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
261 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
263 fsp_to_string (const struct statfs *fsp)
265 # if defined HAVE_F_FSTYPENAME_IN_STATFS
266 return (char *) (fsp->f_fstypename);
268 return fstype_to_string (fsp->f_type);
272 #endif /* MOUNTED_GETMNTINFO */
274 #ifdef MOUNTED_VMOUNT /* AIX. */
276 fstype_to_string (int t)
280 e = getvfsbytype (t);
281 if (!e || !e->vfsent_name)
284 return e->vfsent_name;
286 #endif /* MOUNTED_VMOUNT */
288 /* Return a list of the currently mounted file systems, or NULL on error.
289 Add each entry to the tail of the list so that they stay in order.
290 If NEED_FS_TYPE is true, ensure that the file system type fields in
291 the returned list are valid. Otherwise, they might not be. */
294 read_file_system_list (bool need_fs_type)
296 struct mount_entry *mount_list;
297 struct mount_entry *me;
298 struct mount_entry **mtail = &mount_list;
300 #ifdef MOUNTED_LISTMNTENT
302 struct tabmntent *mntlist, *p;
304 struct mount_entry *me;
306 /* the third and fourth arguments could be used to filter mounts,
307 but Crays doesn't seem to have any mounts that we want to
308 remove. Specifically, automount create normal NFS mounts.
311 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
313 for (p = mntlist; p; p = p->next) {
315 me = xmalloc (sizeof *me);
316 me->me_devname = xstrdup (mnt->mnt_fsname);
317 me->me_mountdir = xstrdup (mnt->mnt_dir);
318 me->me_type = xstrdup (mnt->mnt_type);
319 me->me_type_malloced = 1;
320 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
321 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
324 mtail = &me->me_next;
326 freemntlist (mntlist);
330 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
333 char *table = MOUNTED;
337 fp = setmntent (table, "r");
341 while ((mnt = getmntent (fp)))
343 me = xmalloc (sizeof *me);
344 me->me_devname = xstrdup (mnt->mnt_fsname);
345 me->me_mountdir = xstrdup (mnt->mnt_dir);
346 me->me_type = xstrdup (mnt->mnt_type);
347 me->me_type_malloced = 1;
348 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
349 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
350 devopt = strstr (mnt->mnt_opts, "dev=");
352 me->me_dev = strtoul (devopt + 4, NULL, 16);
354 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
356 /* Add to the linked list. */
358 mtail = &me->me_next;
361 if (endmntent (fp) == 0)
364 #endif /* MOUNTED_GETMNTENT1. */
366 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
371 entries = getmntinfo (&fsp, MNT_NOWAIT);
374 for (; entries-- > 0; fsp++)
376 char *fs_type = fsp_to_string (fsp);
378 me = xmalloc (sizeof *me);
379 me->me_devname = xstrdup (fsp->f_mntfromname);
380 me->me_mountdir = xstrdup (fsp->f_mntonname);
381 me->me_type = fs_type;
382 me->me_type_malloced = 0;
383 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
384 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
385 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
387 /* Add to the linked list. */
389 mtail = &me->me_next;
392 #endif /* MOUNTED_GETMNTINFO */
394 #ifdef MOUNTED_GETMNT /* Ultrix. */
401 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
404 me = xmalloc (sizeof *me);
405 me->me_devname = xstrdup (fsd.fd_req.devname);
406 me->me_mountdir = xstrdup (fsd.fd_req.path);
407 me->me_type = gt_names[fsd.fd_req.fstype];
408 me->me_type_malloced = 0;
409 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
410 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
411 me->me_dev = fsd.fd_req.dev;
413 /* Add to the linked list. */
415 mtail = &me->me_next;
420 #endif /* MOUNTED_GETMNT. */
422 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
424 /* The next_dev() and fs_stat_dev() system calls give the list of
425 all file systems, including the information returned by statvfs()
426 (fs type, total blocks, free blocks etc.), but without the mount
427 point. But on BeOS all file systems except / are mounted in the
428 rootfs, directly under /.
429 The directory name of the mount point is often, but not always,
430 identical to the volume name of the device.
431 We therefore get the list of subdirectories of /, and the list
432 of all file systems, and match the two lists. */
440 struct rootdir_entry *next;
442 struct rootdir_entry *rootdir_list;
443 struct rootdir_entry **rootdir_tail;
448 /* All volumes are mounted in the rootfs, directly under /. */
450 rootdir_tail = &rootdir_list;
451 dirp = opendir ("/");
456 while ((d = readdir (dirp)) != NULL)
461 if (strcmp (d->d_name, "..") == 0)
464 if (strcmp (d->d_name, ".") == 0)
465 name = xstrdup ("/");
468 name = xmalloc (1 + strlen (d->d_name) + 1);
470 strcpy (name + 1, d->d_name);
473 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
475 struct rootdir_entry *re = xmalloc (sizeof *re);
477 re->dev = statbuf.st_dev;
478 re->ino = statbuf.st_ino;
480 /* Add to the linked list. */
482 rootdir_tail = &re->next;
489 *rootdir_tail = NULL;
491 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
492 if (fs_stat_dev (dev, &fi) >= 0)
494 /* Note: fi.dev == dev. */
495 struct rootdir_entry *re;
497 for (re = rootdir_list; re; re = re->next)
498 if (re->dev == fi.dev && re->ino == fi.root)
501 me = xmalloc (sizeof *me);
502 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
503 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
504 me->me_type = xstrdup (fi.fsh_name);
505 me->me_type_malloced = 1;
508 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
510 /* Add to the linked list. */
512 mtail = &me->me_next;
516 while (rootdir_list != NULL)
518 struct rootdir_entry *re = rootdir_list;
519 rootdir_list = re->next;
524 #endif /* MOUNTED_FS_STAT_DEV */
526 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
530 struct statfs *stats;
532 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
535 if (SIZE_MAX / sizeof *stats <= numsys)
538 bufsize = (1 + numsys) * sizeof *stats;
539 stats = xmalloc (bufsize);
540 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
548 for (counter = 0; counter < numsys; counter++)
550 me = xmalloc (sizeof *me);
551 me->me_devname = xstrdup (stats[counter].f_mntfromname);
552 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
553 me->me_type = xstrdup (FS_TYPE (stats[counter]));
554 me->me_type_malloced = 1;
555 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
556 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
557 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
559 /* Add to the linked list. */
561 mtail = &me->me_next;
566 #endif /* MOUNTED_GETFSSTAT */
568 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
571 char *table = "/etc/mnttab";
574 fp = fopen (table, "r");
578 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
580 me = xmalloc (sizeof *me);
581 # ifdef GETFSTYP /* SVR3. */
582 me->me_devname = xstrdup (mnt.mt_dev);
584 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
585 strcpy (me->me_devname, "/dev/");
586 strcpy (me->me_devname + 5, mnt.mt_dev);
588 me->me_mountdir = xstrdup (mnt.mt_filsys);
589 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
591 me->me_type_malloced = 0;
592 # ifdef GETFSTYP /* SVR3. */
596 char typebuf[FSTYPSZ];
598 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
599 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
601 me->me_type = xstrdup (typebuf);
602 me->me_type_malloced = 1;
606 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
607 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
609 /* Add to the linked list. */
611 mtail = &me->me_next;
616 /* The last fread() call must have failed. */
617 int saved_errno = errno;
623 if (fclose (fp) == EOF)
626 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
628 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
630 struct mntent **mnttbl = getmnttbl (), **ent;
631 for (ent=mnttbl;*ent;ent++)
633 me = xmalloc (sizeof *me);
634 me->me_devname = xstrdup ( (*ent)->mt_resource);
635 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
636 me->me_type = xstrdup ((*ent)->mt_fstype);
637 me->me_type_malloced = 1;
638 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
639 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
640 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
642 /* Add to the linked list. */
644 mtail = &me->me_next;
650 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
653 char *table = MNTTAB;
658 # if defined F_RDLCK && defined F_SETLKW
659 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
660 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
661 for this file name, we should use their macro name instead.
662 (Why not just lock MNTTAB directly? We don't know.) */
664 # define MNTTAB_LOCK "/etc/.mnttab.lock"
666 lockfd = open (MNTTAB_LOCK, O_RDONLY);
670 flock.l_type = F_RDLCK;
671 flock.l_whence = SEEK_SET;
674 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
677 int saved_errno = errno;
683 else if (errno != ENOENT)
688 fp = fopen (table, "r");
693 while ((ret = getmntent (fp, &mnt)) == 0)
695 me = xmalloc (sizeof *me);
696 me->me_devname = xstrdup (mnt.mnt_special);
697 me->me_mountdir = xstrdup (mnt.mnt_mountp);
698 me->me_type = xstrdup (mnt.mnt_fstype);
699 me->me_type_malloced = 1;
700 me->me_dummy = MNT_IGNORE (&mnt) != 0;
701 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
702 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
704 /* Add to the linked list. */
706 mtail = &me->me_next;
709 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
712 if (0 <= lockfd && close (lockfd) != 0)
721 #endif /* MOUNTED_GETMNTENT2. */
723 #ifdef MOUNTED_VMOUNT /* AIX. */
726 char *entries, *thisent;
731 /* Ask how many bytes to allocate for the mounted file system info. */
732 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
734 entries = xmalloc (bufsize);
736 /* Get the list of mounted file systems. */
737 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
740 int saved_errno = errno;
746 for (i = 0, thisent = entries;
748 i++, thisent += vmp->vmt_length)
750 char *options, *ignore;
752 vmp = (struct vmount *) thisent;
753 me = xmalloc (sizeof *me);
754 if (vmp->vmt_flags & MNT_REMOTE)
759 /* Prepend the remote dirname. */
760 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
761 dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
762 me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
763 strcpy (me->me_devname, host);
764 strcat (me->me_devname, ":");
765 strcat (me->me_devname, dir);
770 me->me_devname = xstrdup (thisent +
771 vmp->vmt_data[VMT_OBJECT].vmt_off);
773 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
774 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
775 me->me_type_malloced = 1;
776 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
777 ignore = strstr (options, "ignore");
778 me->me_dummy = (ignore
779 && (ignore == options || ignore[-1] == ',')
780 && (ignore[sizeof "ignore" - 1] == ','
781 || ignore[sizeof "ignore" - 1] == '\0'));
782 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
784 /* Add to the linked list. */
786 mtail = &me->me_next;
790 #endif /* MOUNTED_VMOUNT. */
798 int saved_errno = errno;
803 me = mount_list->me_next;
804 free (mount_list->me_devname);
805 free (mount_list->me_mountdir);
806 if (mount_list->me_type_malloced)
807 free (mount_list->me_type);