1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997-2001 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>
24 #include "mountlist.h"
31 #if defined STDC_HEADERS || defined HAVE_STRING_H
58 # include <sys/param.h>
61 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
63 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
66 # include <sys/mount.h>
68 # if HAVE_SYS_FS_TYPES_H
69 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
71 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
72 # define FS_TYPE(Ent) ((Ent).f_fstypename)
74 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
76 #endif /* MOUNTED_GETFSSTAT */
78 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
81 # if defined _PATH_MOUNTED /* GNU libc */
82 # define MOUNTED _PATH_MOUNTED
84 # if defined MNT_MNTTAB /* HP-UX. */
85 # define MOUNTED MNT_MNTTAB
87 # if defined MNTTABNAME /* Dynix. */
88 # define MOUNTED MNTTABNAME
93 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
94 # include <sys/mount.h>
97 #ifdef MOUNTED_GETMNT /* Ultrix. */
98 # include <sys/mount.h>
99 # include <sys/fs_types.h>
102 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
103 # include <fs_info.h>
107 #ifdef MOUNTED_FREAD /* SVR2. */
111 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
113 # include <sys/fstyp.h>
114 # include <sys/statfs.h>
117 #ifdef MOUNTED_LISTMNTENT
121 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
122 # include <sys/mnttab.h>
125 #ifdef MOUNTED_VMOUNT /* AIX. */
127 # include <sys/vfs.h>
131 /* So special that it's not worth putting this in autoconf. */
132 # undef MOUNTED_FREAD_FSTYP
133 # define MOUNTED_GETMNTTBL
136 #if HAVE_SYS_MNTENT_H
137 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
138 # include <sys/mntent.h>
141 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
142 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
144 # define MNT_IGNORE(M) 0
147 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
148 /* Return the value of the hexadecimal number represented by CP.
149 No prefix (like '0x') or suffix (like 'h') is expected to be
151 /* FIXME: this can overflow */
161 if (*cp >= 'a' && *cp <= 'f')
162 val = val * 16 + *cp - 'a' + 10;
163 else if (*cp >= 'A' && *cp <= 'F')
164 val = val * 16 + *cp - 'A' + 10;
165 else if (*cp >= '0' && *cp <= '9')
166 val = val * 16 + *cp - '0';
173 #endif /* MOUNTED_GETMNTENT1. */
175 #if MOUNTED_GETMNTINFO
177 # if ! HAVE_F_FSTYPENAME_IN_STATFS
179 fstype_to_string (short t)
271 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
273 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
275 fsp_to_string (const struct statfs *fsp)
277 # if defined HAVE_F_FSTYPENAME_IN_STATFS
278 return (char *) (fsp->f_fstypename);
280 return fstype_to_string (fsp->f_type);
284 #endif /* MOUNTED_GETMNTINFO */
286 #ifdef MOUNTED_VMOUNT /* AIX. */
288 fstype_to_string (int t)
292 e = getvfsbytype (t);
293 if (!e || !e->vfsent_name)
296 return e->vfsent_name;
298 #endif /* MOUNTED_VMOUNT */
300 /* Return a list of the currently mounted filesystems, or NULL on error.
301 Add each entry to the tail of the list so that they stay in order.
302 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
303 the returned list are valid. Otherwise, they might not be. */
306 read_filesystem_list (int need_fs_type)
308 struct mount_entry *mount_list;
309 struct mount_entry *me;
310 struct mount_entry **mtail = &mount_list;
312 #ifdef MOUNTED_LISTMNTENT
314 struct tabmntent *mntlist, *p;
316 struct mount_entry *me;
318 /* the third and fourth arguments could be used to filter mounts,
319 but Crays doesn't seem to have any mounts that we want to
320 remove. Specifically, automount create normal NFS mounts.
323 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
325 for (p = mntlist; p; p = p->next) {
327 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
328 me->me_devname = xstrdup(mnt->mnt_fsname);
329 me->me_mountdir = xstrdup(mnt->mnt_dir);
330 me->me_type = xstrdup(mnt->mnt_type);
331 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
332 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
335 mtail = &me->me_next;
337 freemntlist(mntlist);
341 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
344 char *table = MOUNTED;
348 fp = setmntent (table, "r");
352 while ((mnt = getmntent (fp)))
354 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
355 me->me_devname = xstrdup (mnt->mnt_fsname);
356 me->me_mountdir = xstrdup (mnt->mnt_dir);
357 me->me_type = xstrdup (mnt->mnt_type);
358 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
359 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
360 devopt = strstr (mnt->mnt_opts, "dev=");
363 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
364 me->me_dev = xatoi (devopt + 6);
366 me->me_dev = xatoi (devopt + 4);
369 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
371 /* Add to the linked list. */
373 mtail = &me->me_next;
376 if (endmntent (fp) == 0)
379 #endif /* MOUNTED_GETMNTENT1. */
381 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
386 entries = getmntinfo (&fsp, MNT_NOWAIT);
389 for (; entries-- > 0; fsp++)
391 char *fs_type = fsp_to_string (fsp);
393 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
394 me->me_devname = xstrdup (fsp->f_mntfromname);
395 me->me_mountdir = xstrdup (fsp->f_mntonname);
396 me->me_type = fs_type;
397 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
398 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
399 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
401 /* Add to the linked list. */
403 mtail = &me->me_next;
406 #endif /* MOUNTED_GETMNTINFO */
408 #ifdef MOUNTED_GETMNT /* Ultrix. */
415 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
418 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
419 me->me_devname = xstrdup (fsd.fd_req.devname);
420 me->me_mountdir = xstrdup (fsd.fd_req.path);
421 me->me_type = gt_names[fsd.fd_req.fstype];
422 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
423 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
424 me->me_dev = fsd.fd_req.dev;
426 /* Add to the linked list. */
428 mtail = &me->me_next;
433 #endif /* MOUNTED_GETMNT. */
435 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
437 /* The next_dev() and fs_stat_dev() system calls give the list of
438 all filesystems, including the information returned by statvfs()
439 (fs type, total blocks, free blocks etc.), but without the mount
440 point. But on BeOS all filesystems except / are mounted in the
441 rootfs, directly under /.
442 The directory name of the mount point is often, but not always,
443 identical to the volume name of the device.
444 We therefore get the list of subdirectories of /, and the list
445 of all filesystems, and match the two lists. */
453 struct rootdir_entry *next;
455 struct rootdir_entry *rootdir_list;
456 struct rootdir_entry **rootdir_tail;
461 /* All volumes are mounted in the rootfs, directly under /. */
463 rootdir_tail = &rootdir_list;
464 dirp = opendir ("/");
469 while ((d = readdir (dirp)) != NULL)
474 if (strcmp (d->d_name, "..") == 0)
477 if (strcmp (d->d_name, ".") == 0)
478 name = xstrdup ("/");
481 name = xmalloc (1 + strlen (d->d_name) + 1);
483 strcpy (name + 1, d->d_name);
486 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
488 struct rootdir_entry *re;
490 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
492 re->dev = statbuf.st_dev;
493 re->ino = statbuf.st_ino;
495 /* Add to the linked list. */
497 rootdir_tail = &re->next;
504 *rootdir_tail = NULL;
506 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
507 if (fs_stat_dev (dev, &fi) >= 0)
509 /* Note: fi.dev == dev. */
510 struct rootdir_entry *re;
512 for (re = rootdir_list; re; re = re->next)
513 if (re->dev == fi.dev && re->ino == fi.root)
516 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
517 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
518 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
519 me->me_type = xstrdup (fi.fsh_name);
522 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
524 /* Add to the linked list. */
526 mtail = &me->me_next;
530 while (rootdir_list != NULL)
532 struct rootdir_entry *re = rootdir_list;
533 rootdir_list = re->next;
538 #endif /* MOUNTED_FS_STAT_DEV */
540 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
542 int numsys, counter, bufsize;
543 struct statfs *stats;
545 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
549 bufsize = (1 + numsys) * sizeof (struct statfs);
550 stats = (struct statfs *)xmalloc (bufsize);
551 numsys = getfsstat (stats, bufsize, MNT_WAIT);
559 for (counter = 0; counter < numsys; counter++)
561 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
562 me->me_devname = xstrdup (stats[counter].f_mntfromname);
563 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
564 me->me_type = xstrdup (FS_TYPE (stats[counter]));
565 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
566 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
567 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
569 /* Add to the linked list. */
571 mtail = &me->me_next;
576 #endif /* MOUNTED_GETFSSTAT */
578 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
581 char *table = "/etc/mnttab";
584 fp = fopen (table, "r");
588 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
590 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
591 # ifdef GETFSTYP /* SVR3. */
592 me->me_devname = xstrdup (mnt.mt_dev);
594 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
595 strcpy (me->me_devname, "/dev/");
596 strcpy (me->me_devname + 5, mnt.mt_dev);
598 me->me_mountdir = xstrdup (mnt.mt_filsys);
599 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
601 # ifdef GETFSTYP /* SVR3. */
605 char typebuf[FSTYPSZ];
607 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
608 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
609 me->me_type = xstrdup (typebuf);
612 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
613 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
615 /* Add to the linked list. */
617 mtail = &me->me_next;
622 int saved_errno = errno;
628 if (fclose (fp) == EOF)
631 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
633 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
635 struct mntent **mnttbl=getmnttbl(),**ent;
636 for (ent=mnttbl;*ent;ent++)
638 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
639 me->me_devname = xstrdup ( (*ent)->mt_resource);
640 me->me_mountdir = xstrdup( (*ent)->mt_directory);
641 me->me_type = xstrdup ((*ent)->mt_fstype);
642 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
643 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
644 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
646 /* Add to the linked list. */
648 mtail = &me->me_next;
654 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
657 char *table = MNTTAB;
662 # if defined F_RDLCK && defined F_SETLKW
663 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
664 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
665 for this file name, we should use their macro name instead.
666 (Why not just lock MNTTAB directly? We don't know.) */
668 # define MNTTAB_LOCK "/etc/.mnttab.lock"
670 lockfd = open (MNTTAB_LOCK, O_RDONLY);
674 flock.l_type = F_RDLCK;
675 flock.l_whence = SEEK_SET;
678 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
681 int saved_errno = errno;
687 else if (errno != ENOENT)
692 fp = fopen (table, "r");
697 while ((ret = getmntent (fp, &mnt)) == 0)
699 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
700 me->me_devname = xstrdup (mnt.mnt_special);
701 me->me_mountdir = xstrdup (mnt.mnt_mountp);
702 me->me_type = xstrdup (mnt.mnt_fstype);
703 me->me_dummy = MNT_IGNORE (&mnt) != 0;
704 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
705 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
707 /* Add to the linked list. */
709 mtail = &me->me_next;
712 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
715 if (0 <= lockfd && close (lockfd) != 0)
724 #endif /* MOUNTED_GETMNTENT2. */
726 #ifdef MOUNTED_VMOUNT /* AIX. */
729 char *entries, *thisent;
732 /* Ask how many bytes to allocate for the mounted filesystem info. */
733 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
734 entries = xmalloc (bufsize);
736 /* Get the list of mounted filesystems. */
737 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
739 for (thisent = entries; thisent < entries + bufsize;
740 thisent += vmp->vmt_length)
742 char *options, *ignore;
744 vmp = (struct vmount *) thisent;
745 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
746 if (vmp->vmt_flags & MNT_REMOTE)
751 /* Prepend the remote pathname. */
752 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
753 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
754 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
755 strcpy (me->me_devname, host);
756 strcat (me->me_devname, ":");
757 strcat (me->me_devname, path);
762 me->me_devname = xstrdup (thisent +
763 vmp->vmt_data[VMT_OBJECT].vmt_off);
765 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
766 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
767 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
768 ignore = strstr (options, "ignore");
769 me->me_dummy = (ignore
770 && (ignore == options || ignore[-1] == ',')
771 && (ignore[sizeof "ignore" - 1] == ','
772 || ignore[sizeof "ignore" - 1] == '\0'));
773 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
775 /* Add to the linked list. */
777 mtail = &me->me_next;
781 #endif /* MOUNTED_VMOUNT. */
789 int saved_errno = errno;
794 me = mount_list->me_next;
795 free (mount_list->me_devname);
796 free (mount_list->me_mountdir);
797 /* FIXME: me_type is not always malloced. */