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 /* __alpha running OSF_1 */
62 # include <sys/mount.h>
63 # include <sys/fs_types.h>
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>
129 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
130 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
132 # define MNT_IGNORE(M) 0
135 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
136 /* Return the value of the hexadecimal number represented by CP.
137 No prefix (like '0x') or suffix (like 'h') is expected to be
139 /* FIXME: this can overflow */
149 if (*cp >= 'a' && *cp <= 'f')
150 val = val * 16 + *cp - 'a' + 10;
151 else if (*cp >= 'A' && *cp <= 'F')
152 val = val * 16 + *cp - 'A' + 10;
153 else if (*cp >= '0' && *cp <= '9')
154 val = val * 16 + *cp - '0';
161 #endif /* MOUNTED_GETMNTENT1. */
163 #if MOUNTED_GETMNTINFO
165 # if ! HAVE_F_FSTYPENAME_IN_STATFS
167 fstype_to_string (short 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 filesystems, 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 nonzero, ensure that the filesystem type fields in
291 the returned list are valid. Otherwise, they might not be. */
294 read_filesystem_list (int 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 = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
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_dummy = ME_DUMMY (me->me_devname, me->me_type);
320 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
323 mtail = &me->me_next;
325 freemntlist(mntlist);
329 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
332 char *table = MOUNTED;
336 fp = setmntent (table, "r");
340 while ((mnt = getmntent (fp)))
342 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
343 me->me_devname = xstrdup (mnt->mnt_fsname);
344 me->me_mountdir = xstrdup (mnt->mnt_dir);
345 me->me_type = xstrdup (mnt->mnt_type);
346 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
347 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
348 devopt = strstr (mnt->mnt_opts, "dev=");
351 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
352 me->me_dev = xatoi (devopt + 6);
354 me->me_dev = xatoi (devopt + 4);
357 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
359 /* Add to the linked list. */
361 mtail = &me->me_next;
364 if (endmntent (fp) == 0)
367 #endif /* MOUNTED_GETMNTENT1. */
369 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
374 entries = getmntinfo (&fsp, MNT_NOWAIT);
377 for (; entries-- > 0; fsp++)
379 char *fs_type = fsp_to_string (fsp);
381 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
382 me->me_devname = xstrdup (fsp->f_mntfromname);
383 me->me_mountdir = xstrdup (fsp->f_mntonname);
384 me->me_type = fs_type;
385 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
386 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
387 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
389 /* Add to the linked list. */
391 mtail = &me->me_next;
394 #endif /* MOUNTED_GETMNTINFO */
396 #ifdef MOUNTED_GETMNT /* Ultrix. */
403 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
406 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
407 me->me_devname = xstrdup (fsd.fd_req.devname);
408 me->me_mountdir = xstrdup (fsd.fd_req.path);
409 me->me_type = gt_names[fsd.fd_req.fstype];
410 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
411 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
412 me->me_dev = fsd.fd_req.dev;
414 /* Add to the linked list. */
416 mtail = &me->me_next;
421 #endif /* MOUNTED_GETMNT. */
423 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
425 /* The next_dev() and fs_stat_dev() system calls give the list of
426 all filesystems, including the information returned by statvfs()
427 (fs type, total blocks, free blocks etc.), but without the mount
428 point. But on BeOS all filesystems except / are mounted in the
429 rootfs, directly under /.
430 The directory name of the mount point is often, but not always,
431 identical to the volume name of the device.
432 We therefore get the list of subdirectories of /, and the list
433 of all filesystems, and match the two lists. */
441 struct rootdir_entry *next;
443 struct rootdir_entry *rootdir_list;
444 struct rootdir_entry **rootdir_tail;
449 /* All volumes are mounted in the rootfs, directly under /. */
451 rootdir_tail = &rootdir_list;
452 dirp = opendir ("/");
457 while ((d = readdir (dirp)) != NULL)
462 if (strcmp (d->d_name, "..") == 0)
465 if (strcmp (d->d_name, ".") == 0)
466 name = xstrdup ("/");
469 name = xmalloc (1 + strlen (d->d_name) + 1);
471 strcpy (name + 1, d->d_name);
474 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
476 struct rootdir_entry *re;
478 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
480 re->dev = statbuf.st_dev;
481 re->ino = statbuf.st_ino;
483 /* Add to the linked list. */
485 rootdir_tail = &re->next;
492 *rootdir_tail = NULL;
494 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
495 if (fs_stat_dev (dev, &fi) >= 0)
497 /* Note: fi.dev == dev. */
498 struct rootdir_entry *re;
500 for (re = rootdir_list; re; re = re->next)
501 if (re->dev == fi.dev && re->ino == fi.root)
504 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
505 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
506 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
507 me->me_type = xstrdup (fi.fsh_name);
510 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
512 /* Add to the linked list. */
514 mtail = &me->me_next;
518 while (rootdir_list != NULL)
520 struct rootdir_entry *re = rootdir_list;
521 rootdir_list = re->next;
526 #endif /* MOUNTED_FS_STAT_DEV */
528 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
530 int numsys, counter, bufsize;
531 struct statfs *stats;
533 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
537 bufsize = (1 + numsys) * sizeof (struct statfs);
538 stats = (struct statfs *)xmalloc (bufsize);
539 numsys = getfsstat (stats, bufsize, MNT_WAIT);
547 for (counter = 0; counter < numsys; counter++)
549 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
550 me->me_devname = xstrdup (stats[counter].f_mntfromname);
551 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
552 me->me_type = mnt_names[stats[counter].f_type];
553 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
554 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
555 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
557 /* Add to the linked list. */
559 mtail = &me->me_next;
564 #endif /* MOUNTED_GETFSSTAT */
566 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
569 char *table = "/etc/mnttab";
572 fp = fopen (table, "r");
576 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
578 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
579 # ifdef GETFSTYP /* SVR3. */
580 me->me_devname = xstrdup (mnt.mt_dev);
582 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
583 strcpy (me->me_devname, "/dev/");
584 strcpy (me->me_devname + 5, mnt.mt_dev);
586 me->me_mountdir = xstrdup (mnt.mt_filsys);
587 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
589 # ifdef GETFSTYP /* SVR3. */
593 char typebuf[FSTYPSZ];
595 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
596 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
597 me->me_type = xstrdup (typebuf);
600 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
601 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
603 /* Add to the linked list. */
605 mtail = &me->me_next;
610 int saved_errno = errno;
616 if (fclose (fp) == EOF)
619 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
621 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
623 struct mntent **mnttbl=getmnttbl(),**ent;
624 for (ent=mnttbl;*ent;ent++)
626 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
627 me->me_devname = xstrdup ( (*ent)->mt_resource);
628 me->me_mountdir = xstrdup( (*ent)->mt_directory);
629 me->me_type = xstrdup ((*ent)->mt_fstype);
630 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
631 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
632 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
634 /* Add to the linked list. */
636 mtail = &me->me_next;
642 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
645 char *table = MNTTAB;
650 # if defined F_RDLCK && defined F_SETLKW
651 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
652 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
653 for this file name, we should use their macro name instead.
654 (Why not just lock MNTTAB directly? We don't know.) */
656 # define MNTTAB_LOCK "/etc/.mnttab.lock"
658 lockfd = open (MNTTAB_LOCK, O_RDONLY);
662 flock.l_type = F_RDLCK;
663 flock.l_whence = SEEK_SET;
666 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
669 int saved_errno = errno;
675 else if (errno != ENOENT)
680 fp = fopen (table, "r");
685 while ((ret = getmntent (fp, &mnt)) == 0)
687 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
688 me->me_devname = xstrdup (mnt.mnt_special);
689 me->me_mountdir = xstrdup (mnt.mnt_mountp);
690 me->me_type = xstrdup (mnt.mnt_fstype);
691 me->me_dummy = MNT_IGNORE (&mnt) != 0;
692 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
693 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
695 /* Add to the linked list. */
697 mtail = &me->me_next;
700 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
703 if (0 <= lockfd && close (lockfd) != 0)
712 #endif /* MOUNTED_GETMNTENT2. */
714 #ifdef MOUNTED_VMOUNT /* AIX. */
717 char *entries, *thisent;
720 /* Ask how many bytes to allocate for the mounted filesystem info. */
721 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
722 entries = xmalloc (bufsize);
724 /* Get the list of mounted filesystems. */
725 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
727 for (thisent = entries; thisent < entries + bufsize;
728 thisent += vmp->vmt_length)
730 char *options, *ignore;
732 vmp = (struct vmount *) thisent;
733 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
734 if (vmp->vmt_flags & MNT_REMOTE)
739 /* Prepend the remote pathname. */
740 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
741 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
742 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
743 strcpy (me->me_devname, host);
744 strcat (me->me_devname, ":");
745 strcat (me->me_devname, path);
750 me->me_devname = xstrdup (thisent +
751 vmp->vmt_data[VMT_OBJECT].vmt_off);
753 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
754 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
755 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
756 ignore = strstr (options, "ignore");
757 me->me_dummy = (ignore
758 && (ignore == options || ignore[-1] == ',')
759 && (ignore[sizeof "ignore" - 1] == ','
760 || ignore[sizeof "ignore" - 1] == '\0'));
761 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
763 /* Add to the linked list. */
765 mtail = &me->me_next;
769 #endif /* MOUNTED_VMOUNT. */
777 int saved_errno = errno;
782 me = mount_list->me_next;
783 free (mount_list->me_devname);
784 free (mount_list->me_mountdir);
785 /* FIXME: me_type is not always malloced. */