1 /* mountlist.c -- return a list of mounted file systems
2 Copyright (C) 1991, 1992, 1997-2004 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include <sys/types.h>
44 # include <sys/param.h>
47 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
49 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
50 NGROUPS is used as an array dimension in ucred.h */
51 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
54 # include <sys/mount.h>
56 # if HAVE_SYS_FS_TYPES_H
57 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
59 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
60 # define FS_TYPE(Ent) ((Ent).f_fstypename)
62 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
64 #endif /* MOUNTED_GETFSSTAT */
66 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
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_GETMNT /* Ultrix. */
86 # include <sys/mount.h>
87 # include <sys/fs_types.h>
90 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
95 #ifdef MOUNTED_FREAD /* SVR2. */
99 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
101 # include <sys/fstyp.h>
102 # include <sys/statfs.h>
105 #ifdef MOUNTED_LISTMNTENT
109 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
110 # include <sys/mnttab.h>
113 #ifdef MOUNTED_VMOUNT /* AIX. */
115 # include <sys/vfs.h>
119 /* So special that it's not worth putting this in autoconf. */
120 # undef MOUNTED_FREAD_FSTYP
121 # define MOUNTED_GETMNTTBL
124 #if HAVE_SYS_MNTENT_H
125 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
126 # include <sys/mntent.h>
130 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
131 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
133 # define MNT_IGNORE(M) 0
136 #include "mountlist.h"
139 # include "unlocked-io.h"
143 # define SIZE_MAX ((size_t) -1)
146 #if MOUNTED_GETMNTINFO
148 # if ! HAVE_F_FSTYPENAME_IN_STATFS
150 fstype_to_string (short int t)
242 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
244 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
246 fsp_to_string (const struct statfs *fsp)
248 # if defined HAVE_F_FSTYPENAME_IN_STATFS
249 return (char *) (fsp->f_fstypename);
251 return fstype_to_string (fsp->f_type);
255 #endif /* MOUNTED_GETMNTINFO */
257 #ifdef MOUNTED_VMOUNT /* AIX. */
259 fstype_to_string (int t)
263 e = getvfsbytype (t);
264 if (!e || !e->vfsent_name)
267 return e->vfsent_name;
269 #endif /* MOUNTED_VMOUNT */
271 /* Return a list of the currently mounted file systems, or NULL on error.
272 Add each entry to the tail of the list so that they stay in order.
273 If NEED_FS_TYPE is true, ensure that the file system type fields in
274 the returned list are valid. Otherwise, they might not be. */
277 read_file_system_list (bool need_fs_type)
279 struct mount_entry *mount_list;
280 struct mount_entry *me;
281 struct mount_entry **mtail = &mount_list;
283 #ifdef MOUNTED_LISTMNTENT
285 struct tabmntent *mntlist, *p;
287 struct mount_entry *me;
289 /* the third and fourth arguments could be used to filter mounts,
290 but Crays doesn't seem to have any mounts that we want to
291 remove. Specifically, automount create normal NFS mounts.
294 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
296 for (p = mntlist; p; p = p->next) {
298 me = xmalloc (sizeof *me);
299 me->me_devname = xstrdup (mnt->mnt_fsname);
300 me->me_mountdir = xstrdup (mnt->mnt_dir);
301 me->me_type = xstrdup (mnt->mnt_type);
302 me->me_type_malloced = 1;
303 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
304 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
307 mtail = &me->me_next;
309 freemntlist (mntlist);
313 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
316 char *table = MOUNTED;
320 fp = setmntent (table, "r");
324 while ((mnt = getmntent (fp)))
326 me = xmalloc (sizeof *me);
327 me->me_devname = xstrdup (mnt->mnt_fsname);
328 me->me_mountdir = xstrdup (mnt->mnt_dir);
329 me->me_type = xstrdup (mnt->mnt_type);
330 me->me_type_malloced = 1;
331 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
332 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
333 devopt = strstr (mnt->mnt_opts, "dev=");
335 me->me_dev = strtoul (devopt + 4, NULL, 16);
337 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
339 /* Add to the linked list. */
341 mtail = &me->me_next;
344 if (endmntent (fp) == 0)
347 #endif /* MOUNTED_GETMNTENT1. */
349 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
354 entries = getmntinfo (&fsp, MNT_NOWAIT);
357 for (; entries-- > 0; fsp++)
359 char *fs_type = fsp_to_string (fsp);
361 me = xmalloc (sizeof *me);
362 me->me_devname = xstrdup (fsp->f_mntfromname);
363 me->me_mountdir = xstrdup (fsp->f_mntonname);
364 me->me_type = fs_type;
365 me->me_type_malloced = 0;
366 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
367 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
368 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
370 /* Add to the linked list. */
372 mtail = &me->me_next;
375 #endif /* MOUNTED_GETMNTINFO */
377 #ifdef MOUNTED_GETMNT /* Ultrix. */
384 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
387 me = xmalloc (sizeof *me);
388 me->me_devname = xstrdup (fsd.fd_req.devname);
389 me->me_mountdir = xstrdup (fsd.fd_req.path);
390 me->me_type = gt_names[fsd.fd_req.fstype];
391 me->me_type_malloced = 0;
392 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
393 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
394 me->me_dev = fsd.fd_req.dev;
396 /* Add to the linked list. */
398 mtail = &me->me_next;
403 #endif /* MOUNTED_GETMNT. */
405 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
407 /* The next_dev() and fs_stat_dev() system calls give the list of
408 all file systems, including the information returned by statvfs()
409 (fs type, total blocks, free blocks etc.), but without the mount
410 point. But on BeOS all file systems except / are mounted in the
411 rootfs, directly under /.
412 The directory name of the mount point is often, but not always,
413 identical to the volume name of the device.
414 We therefore get the list of subdirectories of /, and the list
415 of all file systems, and match the two lists. */
423 struct rootdir_entry *next;
425 struct rootdir_entry *rootdir_list;
426 struct rootdir_entry **rootdir_tail;
431 /* All volumes are mounted in the rootfs, directly under /. */
433 rootdir_tail = &rootdir_list;
434 dirp = opendir ("/");
439 while ((d = readdir (dirp)) != NULL)
444 if (strcmp (d->d_name, "..") == 0)
447 if (strcmp (d->d_name, ".") == 0)
448 name = xstrdup ("/");
451 name = xmalloc (1 + strlen (d->d_name) + 1);
453 strcpy (name + 1, d->d_name);
456 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
458 struct rootdir_entry *re = xmalloc (sizeof *re);
460 re->dev = statbuf.st_dev;
461 re->ino = statbuf.st_ino;
463 /* Add to the linked list. */
465 rootdir_tail = &re->next;
472 *rootdir_tail = NULL;
474 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
475 if (fs_stat_dev (dev, &fi) >= 0)
477 /* Note: fi.dev == dev. */
478 struct rootdir_entry *re;
480 for (re = rootdir_list; re; re = re->next)
481 if (re->dev == fi.dev && re->ino == fi.root)
484 me = xmalloc (sizeof *me);
485 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
486 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
487 me->me_type = xstrdup (fi.fsh_name);
488 me->me_type_malloced = 1;
491 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
493 /* Add to the linked list. */
495 mtail = &me->me_next;
499 while (rootdir_list != NULL)
501 struct rootdir_entry *re = rootdir_list;
502 rootdir_list = re->next;
507 #endif /* MOUNTED_FS_STAT_DEV */
509 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
513 struct statfs *stats;
515 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
518 if (SIZE_MAX / sizeof *stats <= numsys)
521 bufsize = (1 + numsys) * sizeof *stats;
522 stats = xmalloc (bufsize);
523 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
531 for (counter = 0; counter < numsys; counter++)
533 me = xmalloc (sizeof *me);
534 me->me_devname = xstrdup (stats[counter].f_mntfromname);
535 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
536 me->me_type = xstrdup (FS_TYPE (stats[counter]));
537 me->me_type_malloced = 1;
538 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
539 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
540 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
542 /* Add to the linked list. */
544 mtail = &me->me_next;
549 #endif /* MOUNTED_GETFSSTAT */
551 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
554 char *table = "/etc/mnttab";
557 fp = fopen (table, "r");
561 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
563 me = xmalloc (sizeof *me);
564 # ifdef GETFSTYP /* SVR3. */
565 me->me_devname = xstrdup (mnt.mt_dev);
567 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
568 strcpy (me->me_devname, "/dev/");
569 strcpy (me->me_devname + 5, mnt.mt_dev);
571 me->me_mountdir = xstrdup (mnt.mt_filsys);
572 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
574 me->me_type_malloced = 0;
575 # ifdef GETFSTYP /* SVR3. */
579 char typebuf[FSTYPSZ];
581 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
582 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
584 me->me_type = xstrdup (typebuf);
585 me->me_type_malloced = 1;
589 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
590 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
592 /* Add to the linked list. */
594 mtail = &me->me_next;
599 /* The last fread() call must have failed. */
600 int saved_errno = errno;
606 if (fclose (fp) == EOF)
609 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
611 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
613 struct mntent **mnttbl = getmnttbl (), **ent;
614 for (ent=mnttbl;*ent;ent++)
616 me = xmalloc (sizeof *me);
617 me->me_devname = xstrdup ( (*ent)->mt_resource);
618 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
619 me->me_type = xstrdup ((*ent)->mt_fstype);
620 me->me_type_malloced = 1;
621 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
622 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
623 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
625 /* Add to the linked list. */
627 mtail = &me->me_next;
633 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
636 char *table = MNTTAB;
641 # if defined F_RDLCK && defined F_SETLKW
642 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
643 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
644 for this file name, we should use their macro name instead.
645 (Why not just lock MNTTAB directly? We don't know.) */
647 # define MNTTAB_LOCK "/etc/.mnttab.lock"
649 lockfd = open (MNTTAB_LOCK, O_RDONLY);
653 flock.l_type = F_RDLCK;
654 flock.l_whence = SEEK_SET;
657 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
660 int saved_errno = errno;
666 else if (errno != ENOENT)
671 fp = fopen (table, "r");
676 while ((ret = getmntent (fp, &mnt)) == 0)
678 me = xmalloc (sizeof *me);
679 me->me_devname = xstrdup (mnt.mnt_special);
680 me->me_mountdir = xstrdup (mnt.mnt_mountp);
681 me->me_type = xstrdup (mnt.mnt_fstype);
682 me->me_type_malloced = 1;
683 me->me_dummy = MNT_IGNORE (&mnt) != 0;
684 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
685 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
687 /* Add to the linked list. */
689 mtail = &me->me_next;
692 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
695 if (0 <= lockfd && close (lockfd) != 0)
704 #endif /* MOUNTED_GETMNTENT2. */
706 #ifdef MOUNTED_VMOUNT /* AIX. */
709 char *entries, *thisent;
714 /* Ask how many bytes to allocate for the mounted file system info. */
715 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
717 entries = xmalloc (bufsize);
719 /* Get the list of mounted file systems. */
720 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
723 int saved_errno = errno;
729 for (i = 0, thisent = entries;
731 i++, thisent += vmp->vmt_length)
733 char *options, *ignore;
735 vmp = (struct vmount *) thisent;
736 me = xmalloc (sizeof *me);
737 if (vmp->vmt_flags & MNT_REMOTE)
742 /* Prepend the remote pathname. */
743 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
744 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
745 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
746 strcpy (me->me_devname, host);
747 strcat (me->me_devname, ":");
748 strcat (me->me_devname, path);
753 me->me_devname = xstrdup (thisent +
754 vmp->vmt_data[VMT_OBJECT].vmt_off);
756 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
757 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
758 me->me_type_malloced = 1;
759 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
760 ignore = strstr (options, "ignore");
761 me->me_dummy = (ignore
762 && (ignore == options || ignore[-1] == ',')
763 && (ignore[sizeof "ignore" - 1] == ','
764 || ignore[sizeof "ignore" - 1] == '\0'));
765 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
767 /* Add to the linked list. */
769 mtail = &me->me_next;
773 #endif /* MOUNTED_VMOUNT. */
781 int saved_errno = errno;
786 me = mount_list->me_next;
787 free (mount_list->me_devname);
788 free (mount_list->me_mountdir);
789 if (mount_list->me_type_malloced)
790 free (mount_list->me_type);