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>
30 # define SIZE_MAX ((size_t) -1)
51 # include <sys/param.h>
54 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
56 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
59 # include <sys/mount.h>
61 # if HAVE_SYS_FS_TYPES_H
62 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
64 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65 # define FS_TYPE(Ent) ((Ent).f_fstypename)
67 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
69 #endif /* MOUNTED_GETFSSTAT */
71 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
74 # if defined _PATH_MOUNTED /* GNU libc */
75 # define MOUNTED _PATH_MOUNTED
77 # if defined MNT_MNTTAB /* HP-UX. */
78 # define MOUNTED MNT_MNTTAB
80 # if defined MNTTABNAME /* Dynix. */
81 # define MOUNTED MNTTABNAME
86 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
87 # include <sys/mount.h>
90 #ifdef MOUNTED_GETMNT /* Ultrix. */
91 # include <sys/mount.h>
92 # include <sys/fs_types.h>
95 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
100 #ifdef MOUNTED_FREAD /* SVR2. */
104 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
106 # include <sys/fstyp.h>
107 # include <sys/statfs.h>
110 #ifdef MOUNTED_LISTMNTENT
114 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
115 # include <sys/mnttab.h>
118 #ifdef MOUNTED_VMOUNT /* AIX. */
120 # include <sys/vfs.h>
124 /* So special that it's not worth putting this in autoconf. */
125 # undef MOUNTED_FREAD_FSTYP
126 # define MOUNTED_GETMNTTBL
129 #if HAVE_SYS_MNTENT_H
130 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
131 # include <sys/mntent.h>
135 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
136 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
138 # define MNT_IGNORE(M) 0
141 #include "mountlist.h"
142 #include "unlocked-io.h"
144 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
145 /* Return the value of the hexadecimal number represented by CP.
146 No prefix (like '0x') or suffix (like 'h') is expected to be
148 /* FIXME: this can overflow */
158 if (*cp >= 'a' && *cp <= 'f')
159 val = val * 16 + *cp - 'a' + 10;
160 else if (*cp >= 'A' && *cp <= 'F')
161 val = val * 16 + *cp - 'A' + 10;
162 else if (*cp >= '0' && *cp <= '9')
163 val = val * 16 + *cp - '0';
170 #endif /* MOUNTED_GETMNTENT1. */
172 #if MOUNTED_GETMNTINFO
174 # if ! HAVE_F_FSTYPENAME_IN_STATFS
176 fstype_to_string (short t)
268 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
270 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
272 fsp_to_string (const struct statfs *fsp)
274 # if defined HAVE_F_FSTYPENAME_IN_STATFS
275 return (char *) (fsp->f_fstypename);
277 return fstype_to_string (fsp->f_type);
281 #endif /* MOUNTED_GETMNTINFO */
283 #ifdef MOUNTED_VMOUNT /* AIX. */
285 fstype_to_string (int t)
289 e = getvfsbytype (t);
290 if (!e || !e->vfsent_name)
293 return e->vfsent_name;
295 #endif /* MOUNTED_VMOUNT */
297 /* Return a list of the currently mounted filesystems, or NULL on error.
298 Add each entry to the tail of the list so that they stay in order.
299 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
300 the returned list are valid. Otherwise, they might not be. */
303 read_filesystem_list (int need_fs_type)
305 struct mount_entry *mount_list;
306 struct mount_entry *me;
307 struct mount_entry **mtail = &mount_list;
309 #ifdef MOUNTED_LISTMNTENT
311 struct tabmntent *mntlist, *p;
313 struct mount_entry *me;
315 /* the third and fourth arguments could be used to filter mounts,
316 but Crays doesn't seem to have any mounts that we want to
317 remove. Specifically, automount create normal NFS mounts.
320 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
322 for (p = mntlist; p; p = p->next) {
324 me = xmalloc (sizeof *me);
325 me->me_devname = xstrdup (mnt->mnt_fsname);
326 me->me_mountdir = xstrdup (mnt->mnt_dir);
327 me->me_type = xstrdup (mnt->mnt_type);
328 me->me_type_malloced = 1;
329 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
330 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
333 mtail = &me->me_next;
335 freemntlist (mntlist);
339 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
342 char *table = MOUNTED;
346 fp = setmntent (table, "r");
350 while ((mnt = getmntent (fp)))
352 me = xmalloc (sizeof *me);
353 me->me_devname = xstrdup (mnt->mnt_fsname);
354 me->me_mountdir = xstrdup (mnt->mnt_dir);
355 me->me_type = xstrdup (mnt->mnt_type);
356 me->me_type_malloced = 1;
357 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
358 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
359 devopt = strstr (mnt->mnt_opts, "dev=");
362 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
363 me->me_dev = xatoi (devopt + 6);
365 me->me_dev = xatoi (devopt + 4);
368 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
370 /* Add to the linked list. */
372 mtail = &me->me_next;
375 if (endmntent (fp) == 0)
378 #endif /* MOUNTED_GETMNTENT1. */
380 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
385 entries = getmntinfo (&fsp, MNT_NOWAIT);
388 for (; entries-- > 0; fsp++)
390 char *fs_type = fsp_to_string (fsp);
392 me = xmalloc (sizeof *me);
393 me->me_devname = xstrdup (fsp->f_mntfromname);
394 me->me_mountdir = xstrdup (fsp->f_mntonname);
395 me->me_type = fs_type;
396 me->me_type_malloced = 0;
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 = xmalloc (sizeof *me);
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_type_malloced = 0;
423 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
424 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
425 me->me_dev = fsd.fd_req.dev;
427 /* Add to the linked list. */
429 mtail = &me->me_next;
434 #endif /* MOUNTED_GETMNT. */
436 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
438 /* The next_dev() and fs_stat_dev() system calls give the list of
439 all filesystems, including the information returned by statvfs()
440 (fs type, total blocks, free blocks etc.), but without the mount
441 point. But on BeOS all filesystems except / are mounted in the
442 rootfs, directly under /.
443 The directory name of the mount point is often, but not always,
444 identical to the volume name of the device.
445 We therefore get the list of subdirectories of /, and the list
446 of all filesystems, and match the two lists. */
454 struct rootdir_entry *next;
456 struct rootdir_entry *rootdir_list;
457 struct rootdir_entry **rootdir_tail;
462 /* All volumes are mounted in the rootfs, directly under /. */
464 rootdir_tail = &rootdir_list;
465 dirp = opendir ("/");
470 while ((d = readdir (dirp)) != NULL)
475 if (strcmp (d->d_name, "..") == 0)
478 if (strcmp (d->d_name, ".") == 0)
479 name = xstrdup ("/");
482 name = xmalloc (1 + strlen (d->d_name) + 1);
484 strcpy (name + 1, d->d_name);
487 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
489 struct rootdir_entry *re = xmalloc (sizeof *re);
491 re->dev = statbuf.st_dev;
492 re->ino = statbuf.st_ino;
494 /* Add to the linked list. */
496 rootdir_tail = &re->next;
503 *rootdir_tail = NULL;
505 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
506 if (fs_stat_dev (dev, &fi) >= 0)
508 /* Note: fi.dev == dev. */
509 struct rootdir_entry *re;
511 for (re = rootdir_list; re; re = re->next)
512 if (re->dev == fi.dev && re->ino == fi.root)
515 me = xmalloc (sizeof *me);
516 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
517 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
518 me->me_type = xstrdup (fi.fsh_name);
519 me->me_type_malloced = 1;
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 */
544 struct statfs *stats;
546 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
549 if (SIZE_MAX / sizeof *stats <= numsys)
552 bufsize = (1 + numsys) * sizeof *stats;
553 stats = xmalloc (bufsize);
554 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
562 for (counter = 0; counter < numsys; counter++)
564 me = xmalloc (sizeof *me);
565 me->me_devname = xstrdup (stats[counter].f_mntfromname);
566 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
567 me->me_type = xstrdup (FS_TYPE (stats[counter]));
568 me->me_type_malloced = 1;
569 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
570 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
571 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
573 /* Add to the linked list. */
575 mtail = &me->me_next;
580 #endif /* MOUNTED_GETFSSTAT */
582 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
585 char *table = "/etc/mnttab";
588 fp = fopen (table, "r");
592 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
594 me = xmalloc (sizeof *me);
595 # ifdef GETFSTYP /* SVR3. */
596 me->me_devname = xstrdup (mnt.mt_dev);
598 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
599 strcpy (me->me_devname, "/dev/");
600 strcpy (me->me_devname + 5, mnt.mt_dev);
602 me->me_mountdir = xstrdup (mnt.mt_filsys);
603 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
605 me->me_type_malloced = 0;
606 # ifdef GETFSTYP /* SVR3. */
610 char typebuf[FSTYPSZ];
612 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
613 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
615 me->me_type = xstrdup (typebuf);
616 me->me_type_malloced = 1;
620 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
621 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
623 /* Add to the linked list. */
625 mtail = &me->me_next;
630 /* The last fread() call must have failed. */
631 int saved_errno = errno;
637 if (fclose (fp) == EOF)
640 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
642 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
644 struct mntent **mnttbl = getmnttbl (), **ent;
645 for (ent=mnttbl;*ent;ent++)
647 me = xmalloc (sizeof *me);
648 me->me_devname = xstrdup ( (*ent)->mt_resource);
649 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
650 me->me_type = xstrdup ((*ent)->mt_fstype);
651 me->me_type_malloced = 1;
652 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
653 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
654 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
656 /* Add to the linked list. */
658 mtail = &me->me_next;
664 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
667 char *table = MNTTAB;
672 # if defined F_RDLCK && defined F_SETLKW
673 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
674 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
675 for this file name, we should use their macro name instead.
676 (Why not just lock MNTTAB directly? We don't know.) */
678 # define MNTTAB_LOCK "/etc/.mnttab.lock"
680 lockfd = open (MNTTAB_LOCK, O_RDONLY);
684 flock.l_type = F_RDLCK;
685 flock.l_whence = SEEK_SET;
688 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
691 int saved_errno = errno;
697 else if (errno != ENOENT)
702 fp = fopen (table, "r");
707 while ((ret = getmntent (fp, &mnt)) == 0)
709 me = xmalloc (sizeof *me);
710 me->me_devname = xstrdup (mnt.mnt_special);
711 me->me_mountdir = xstrdup (mnt.mnt_mountp);
712 me->me_type = xstrdup (mnt.mnt_fstype);
713 me->me_type_malloced = 1;
714 me->me_dummy = MNT_IGNORE (&mnt) != 0;
715 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
716 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
718 /* Add to the linked list. */
720 mtail = &me->me_next;
723 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
726 if (0 <= lockfd && close (lockfd) != 0)
735 #endif /* MOUNTED_GETMNTENT2. */
737 #ifdef MOUNTED_VMOUNT /* AIX. */
740 char *entries, *thisent;
745 /* Ask how many bytes to allocate for the mounted filesystem info. */
746 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
748 entries = xmalloc (bufsize);
750 /* Get the list of mounted filesystems. */
751 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
754 int saved_errno = errno;
760 for (i = 0, thisent = entries;
762 i++, thisent += vmp->vmt_length)
764 char *options, *ignore;
766 vmp = (struct vmount *) thisent;
767 me = xmalloc (sizeof *me);
768 if (vmp->vmt_flags & MNT_REMOTE)
773 /* Prepend the remote pathname. */
774 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
775 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
776 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
777 strcpy (me->me_devname, host);
778 strcat (me->me_devname, ":");
779 strcat (me->me_devname, path);
784 me->me_devname = xstrdup (thisent +
785 vmp->vmt_data[VMT_OBJECT].vmt_off);
787 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
788 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
789 me->me_type_malloced = 1;
790 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
791 ignore = strstr (options, "ignore");
792 me->me_dummy = (ignore
793 && (ignore == options || ignore[-1] == ',')
794 && (ignore[sizeof "ignore" - 1] == ','
795 || ignore[sizeof "ignore" - 1] == '\0'));
796 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
798 /* Add to the linked list. */
800 mtail = &me->me_next;
804 #endif /* MOUNTED_VMOUNT. */
812 int saved_errno = errno;
817 me = mount_list->me_next;
818 free (mount_list->me_devname);
819 free (mount_list->me_mountdir);
820 if (mount_list->me_type_malloced)
821 free (mount_list->me_type);