1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997-2003 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>
31 #if defined STDC_HEADERS || defined HAVE_STRING_H
56 # include <sys/param.h>
59 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
61 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
64 # include <sys/mount.h>
66 # if HAVE_SYS_FS_TYPES_H
67 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
69 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
70 # define FS_TYPE(Ent) ((Ent).f_fstypename)
72 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
74 #endif /* MOUNTED_GETFSSTAT */
76 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
79 # if defined _PATH_MOUNTED /* GNU libc */
80 # define MOUNTED _PATH_MOUNTED
82 # if defined MNT_MNTTAB /* HP-UX. */
83 # define MOUNTED MNT_MNTTAB
85 # if defined MNTTABNAME /* Dynix. */
86 # define MOUNTED MNTTABNAME
91 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
92 # include <sys/mount.h>
95 #ifdef MOUNTED_GETMNT /* Ultrix. */
96 # include <sys/mount.h>
97 # include <sys/fs_types.h>
100 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
101 # include <fs_info.h>
105 #ifdef MOUNTED_FREAD /* SVR2. */
109 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
111 # include <sys/fstyp.h>
112 # include <sys/statfs.h>
115 #ifdef MOUNTED_LISTMNTENT
119 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
120 # include <sys/mnttab.h>
123 #ifdef MOUNTED_VMOUNT /* AIX. */
125 # include <sys/vfs.h>
129 /* So special that it's not worth putting this in autoconf. */
130 # undef MOUNTED_FREAD_FSTYP
131 # define MOUNTED_GETMNTTBL
134 #if HAVE_SYS_MNTENT_H
135 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
136 # include <sys/mntent.h>
140 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
141 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
143 # define MNT_IGNORE(M) 0
146 #include "mountlist.h"
147 #include "unlocked-io.h"
149 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
150 /* Return the value of the hexadecimal number represented by CP.
151 No prefix (like '0x') or suffix (like 'h') is expected to be
153 /* FIXME: this can overflow */
163 if (*cp >= 'a' && *cp <= 'f')
164 val = val * 16 + *cp - 'a' + 10;
165 else if (*cp >= 'A' && *cp <= 'F')
166 val = val * 16 + *cp - 'A' + 10;
167 else if (*cp >= '0' && *cp <= '9')
168 val = val * 16 + *cp - '0';
175 #endif /* MOUNTED_GETMNTENT1. */
177 #if MOUNTED_GETMNTINFO
179 # if ! HAVE_F_FSTYPENAME_IN_STATFS
181 fstype_to_string (short t)
273 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
275 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
277 fsp_to_string (const struct statfs *fsp)
279 # if defined HAVE_F_FSTYPENAME_IN_STATFS
280 return (char *) (fsp->f_fstypename);
282 return fstype_to_string (fsp->f_type);
286 #endif /* MOUNTED_GETMNTINFO */
288 #ifdef MOUNTED_VMOUNT /* AIX. */
290 fstype_to_string (int t)
294 e = getvfsbytype (t);
295 if (!e || !e->vfsent_name)
298 return e->vfsent_name;
300 #endif /* MOUNTED_VMOUNT */
302 /* Return a list of the currently mounted filesystems, or NULL on error.
303 Add each entry to the tail of the list so that they stay in order.
304 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
305 the returned list are valid. Otherwise, they might not be. */
308 read_filesystem_list (int need_fs_type)
310 struct mount_entry *mount_list;
311 struct mount_entry *me;
312 struct mount_entry **mtail = &mount_list;
314 #ifdef MOUNTED_LISTMNTENT
316 struct tabmntent *mntlist, *p;
318 struct mount_entry *me;
320 /* the third and fourth arguments could be used to filter mounts,
321 but Crays doesn't seem to have any mounts that we want to
322 remove. Specifically, automount create normal NFS mounts.
325 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
327 for (p = mntlist; p; p = p->next) {
329 me = xmalloc (sizeof (struct mount_entry));
330 me->me_devname = xstrdup (mnt->mnt_fsname);
331 me->me_mountdir = xstrdup (mnt->mnt_dir);
332 me->me_type = xstrdup (mnt->mnt_type);
333 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
334 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
337 mtail = &me->me_next;
339 freemntlist (mntlist);
343 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
346 char *table = MOUNTED;
350 fp = setmntent (table, "r");
354 while ((mnt = getmntent (fp)))
356 me = xmalloc (sizeof (struct mount_entry));
357 me->me_devname = xstrdup (mnt->mnt_fsname);
358 me->me_mountdir = xstrdup (mnt->mnt_dir);
359 me->me_type = xstrdup (mnt->mnt_type);
360 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
361 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
362 devopt = strstr (mnt->mnt_opts, "dev=");
365 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
366 me->me_dev = xatoi (devopt + 6);
368 me->me_dev = xatoi (devopt + 4);
371 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
373 /* Add to the linked list. */
375 mtail = &me->me_next;
378 if (endmntent (fp) == 0)
381 #endif /* MOUNTED_GETMNTENT1. */
383 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
388 entries = getmntinfo (&fsp, MNT_NOWAIT);
391 for (; entries-- > 0; fsp++)
393 char *fs_type = fsp_to_string (fsp);
395 me = xmalloc (sizeof (struct mount_entry));
396 me->me_devname = xstrdup (fsp->f_mntfromname);
397 me->me_mountdir = xstrdup (fsp->f_mntonname);
398 me->me_type = fs_type;
399 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
400 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
401 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
403 /* Add to the linked list. */
405 mtail = &me->me_next;
408 #endif /* MOUNTED_GETMNTINFO */
410 #ifdef MOUNTED_GETMNT /* Ultrix. */
417 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
420 me = xmalloc (sizeof (struct mount_entry));
421 me->me_devname = xstrdup (fsd.fd_req.devname);
422 me->me_mountdir = xstrdup (fsd.fd_req.path);
423 me->me_type = gt_names[fsd.fd_req.fstype];
424 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
425 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
426 me->me_dev = fsd.fd_req.dev;
428 /* Add to the linked list. */
430 mtail = &me->me_next;
435 #endif /* MOUNTED_GETMNT. */
437 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
439 /* The next_dev() and fs_stat_dev() system calls give the list of
440 all filesystems, including the information returned by statvfs()
441 (fs type, total blocks, free blocks etc.), but without the mount
442 point. But on BeOS all filesystems except / are mounted in the
443 rootfs, directly under /.
444 The directory name of the mount point is often, but not always,
445 identical to the volume name of the device.
446 We therefore get the list of subdirectories of /, and the list
447 of all filesystems, and match the two lists. */
455 struct rootdir_entry *next;
457 struct rootdir_entry *rootdir_list;
458 struct rootdir_entry **rootdir_tail;
463 /* All volumes are mounted in the rootfs, directly under /. */
465 rootdir_tail = &rootdir_list;
466 dirp = opendir ("/");
471 while ((d = readdir (dirp)) != NULL)
476 if (strcmp (d->d_name, "..") == 0)
479 if (strcmp (d->d_name, ".") == 0)
480 name = xstrdup ("/");
483 name = xmalloc (1 + strlen (d->d_name) + 1);
485 strcpy (name + 1, d->d_name);
488 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
490 struct rootdir_entry *re;
492 re = xmalloc (sizeof (struct rootdir_entry));
494 re->dev = statbuf.st_dev;
495 re->ino = statbuf.st_ino;
497 /* Add to the linked list. */
499 rootdir_tail = &re->next;
506 *rootdir_tail = NULL;
508 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
509 if (fs_stat_dev (dev, &fi) >= 0)
511 /* Note: fi.dev == dev. */
512 struct rootdir_entry *re;
514 for (re = rootdir_list; re; re = re->next)
515 if (re->dev == fi.dev && re->ino == fi.root)
518 me = xmalloc (sizeof (struct mount_entry));
519 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
520 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
521 me->me_type = xstrdup (fi.fsh_name);
524 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
526 /* Add to the linked list. */
528 mtail = &me->me_next;
532 while (rootdir_list != NULL)
534 struct rootdir_entry *re = rootdir_list;
535 rootdir_list = re->next;
540 #endif /* MOUNTED_FS_STAT_DEV */
542 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
544 int numsys, counter, bufsize;
545 struct statfs *stats;
547 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
551 bufsize = (1 + numsys) * sizeof (struct statfs);
552 stats = xmalloc (bufsize);
553 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
561 for (counter = 0; counter < numsys; counter++)
563 me = xmalloc (sizeof (struct mount_entry));
564 me->me_devname = xstrdup (stats[counter].f_mntfromname);
565 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
566 me->me_type = xstrdup (FS_TYPE (stats[counter]));
567 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
568 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
569 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
571 /* Add to the linked list. */
573 mtail = &me->me_next;
578 #endif /* MOUNTED_GETFSSTAT */
580 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
583 char *table = "/etc/mnttab";
586 fp = fopen (table, "r");
590 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
592 me = xmalloc (sizeof (struct mount_entry));
593 # ifdef GETFSTYP /* SVR3. */
594 me->me_devname = xstrdup (mnt.mt_dev);
596 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
597 strcpy (me->me_devname, "/dev/");
598 strcpy (me->me_devname + 5, mnt.mt_dev);
600 me->me_mountdir = xstrdup (mnt.mt_filsys);
601 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
603 # ifdef GETFSTYP /* SVR3. */
607 char typebuf[FSTYPSZ];
609 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
610 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
611 me->me_type = xstrdup (typebuf);
614 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
615 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
617 /* Add to the linked list. */
619 mtail = &me->me_next;
624 int saved_errno = errno;
630 if (fclose (fp) == EOF)
633 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
635 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
637 struct mntent **mnttbl = getmnttbl (), **ent;
638 for (ent=mnttbl;*ent;ent++)
640 me = xmalloc (sizeof (struct mount_entry));
641 me->me_devname = xstrdup ( (*ent)->mt_resource);
642 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
643 me->me_type = xstrdup ((*ent)->mt_fstype);
644 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
645 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
646 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
648 /* Add to the linked list. */
650 mtail = &me->me_next;
656 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
659 char *table = MNTTAB;
664 # if defined F_RDLCK && defined F_SETLKW
665 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
666 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
667 for this file name, we should use their macro name instead.
668 (Why not just lock MNTTAB directly? We don't know.) */
670 # define MNTTAB_LOCK "/etc/.mnttab.lock"
672 lockfd = open (MNTTAB_LOCK, O_RDONLY);
676 flock.l_type = F_RDLCK;
677 flock.l_whence = SEEK_SET;
680 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
683 int saved_errno = errno;
689 else if (errno != ENOENT)
694 fp = fopen (table, "r");
699 while ((ret = getmntent (fp, &mnt)) == 0)
701 me = xmalloc (sizeof (struct mount_entry));
702 me->me_devname = xstrdup (mnt.mnt_special);
703 me->me_mountdir = xstrdup (mnt.mnt_mountp);
704 me->me_type = xstrdup (mnt.mnt_fstype);
705 me->me_dummy = MNT_IGNORE (&mnt) != 0;
706 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
707 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
709 /* Add to the linked list. */
711 mtail = &me->me_next;
714 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
717 if (0 <= lockfd && close (lockfd) != 0)
726 #endif /* MOUNTED_GETMNTENT2. */
728 #ifdef MOUNTED_VMOUNT /* AIX. */
731 char *entries, *thisent;
736 /* Ask how many bytes to allocate for the mounted filesystem info. */
737 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
739 entries = xmalloc (bufsize);
741 /* Get the list of mounted filesystems. */
742 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
745 int saved_errno = errno;
751 for (i = 0, thisent = entries;
753 i++, thisent += vmp->vmt_length)
755 char *options, *ignore;
757 vmp = (struct vmount *) thisent;
758 me = xmalloc (sizeof (struct mount_entry));
759 if (vmp->vmt_flags & MNT_REMOTE)
764 /* Prepend the remote pathname. */
765 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
766 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
767 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
768 strcpy (me->me_devname, host);
769 strcat (me->me_devname, ":");
770 strcat (me->me_devname, path);
775 me->me_devname = xstrdup (thisent +
776 vmp->vmt_data[VMT_OBJECT].vmt_off);
778 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
779 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
780 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
781 ignore = strstr (options, "ignore");
782 me->me_dummy = (ignore
783 && (ignore == options || ignore[-1] == ',')
784 && (ignore[sizeof "ignore" - 1] == ','
785 || ignore[sizeof "ignore" - 1] == '\0'));
786 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
788 /* Add to the linked list. */
790 mtail = &me->me_next;
794 #endif /* MOUNTED_VMOUNT. */
802 int saved_errno = errno;
807 me = mount_list->me_next;
808 free (mount_list->me_devname);
809 free (mount_list->me_mountdir);
810 /* FIXME: me_type is not always malloced. */