1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000 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)
59 # include <sys/param.h>
62 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
63 # include <sys/mount.h>
64 # include <sys/fs_types.h>
65 #endif /* MOUNTED_GETFSSTAT */
67 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
69 # if !defined(MOUNTED)
70 # if defined(MNT_MNTTAB) /* HP-UX. */
71 # define MOUNTED MNT_MNTTAB
73 # if defined(MNTTABNAME) /* Dynix. */
74 # define MOUNTED MNTTABNAME
79 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
80 # include <sys/mount.h>
83 #ifdef MOUNTED_GETMNT /* Ultrix. */
84 # include <sys/mount.h>
85 # include <sys/fs_types.h>
88 #ifdef MOUNTED_NEXT_DEV /* BeOS. */
93 #ifdef MOUNTED_FREAD /* SVR2. */
97 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
99 # include <sys/fstyp.h>
100 # include <sys/statfs.h>
103 #ifdef MOUNTED_LISTMNTENT
107 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
108 # include <sys/mnttab.h>
111 #ifdef MOUNTED_VMOUNT /* AIX. */
113 # include <sys/vfs.h>
117 /* So special that it's not worth putting this in autoconf. */
118 # undef MOUNTED_FREAD_FSTYP
119 # define MOUNTED_GETMNTTBL
122 #if HAVE_SYS_MNTENT_H
123 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
124 # include <sys/mntent.h>
127 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
128 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
130 # define MNT_IGNORE(M) 0
133 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
134 /* Return the value of the hexadecimal number represented by CP.
135 No prefix (like '0x') or suffix (like 'h') is expected to be
137 /* FIXME: this can overflow */
147 if (*cp >= 'a' && *cp <= 'f')
148 val = val * 16 + *cp - 'a' + 10;
149 else if (*cp >= 'A' && *cp <= 'F')
150 val = val * 16 + *cp - 'A' + 10;
151 else if (*cp >= '0' && *cp <= '9')
152 val = val * 16 + *cp - '0';
159 #endif /* MOUNTED_GETMNTENT1. */
161 #if MOUNTED_GETMNTINFO
163 # if ! HAVE_F_FSTYPENAME_IN_STATFS
165 fstype_to_string (short t)
257 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
259 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
261 fsp_to_string (const struct statfs *fsp)
263 # if defined HAVE_F_FSTYPENAME_IN_STATFS
264 return fsp->f_fstypename;
266 return fstype_to_string (fsp->f_type);
270 #endif /* MOUNTED_GETMNTINFO */
272 #ifdef MOUNTED_VMOUNT /* AIX. */
274 fstype_to_string (int t)
278 e = getvfsbytype (t);
279 if (!e || !e->vfsent_name)
282 return e->vfsent_name;
284 #endif /* MOUNTED_VMOUNT */
286 /* Return a list of the currently mounted filesystems, or NULL on error.
287 Add each entry to the tail of the list so that they stay in order.
288 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
289 the returned list are valid. Otherwise, they might not be. */
292 read_filesystem_list (int need_fs_type)
294 struct mount_entry *mount_list;
295 struct mount_entry *me;
296 struct mount_entry **mtail = &mount_list;
298 #ifdef MOUNTED_LISTMNTENT
300 struct tabmntent *mntlist, *p;
302 struct mount_entry *me;
304 /* the third and fourth arguments could be used to filter mounts,
305 but Crays doesn't seem to have any mounts that we want to
306 remove. Specifically, automount create normal NFS mounts.
309 if(listmntent(&mntlist, KMTAB, NULL, NULL) < 0)
311 for (p = mntlist; p; p = p->next) {
313 me = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
314 me->me_devname = xstrdup(mnt->mnt_fsname);
315 me->me_mountdir = xstrdup(mnt->mnt_dir);
316 me->me_type = xstrdup(mnt->mnt_type);
317 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
318 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
321 mtail = &me->me_next;
323 freemntlist(mntlist);
327 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
330 char *table = MOUNTED;
334 fp = setmntent (table, "r");
338 while ((mnt = getmntent (fp)))
340 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
341 me->me_devname = xstrdup (mnt->mnt_fsname);
342 me->me_mountdir = xstrdup (mnt->mnt_dir);
343 me->me_type = xstrdup (mnt->mnt_type);
344 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
345 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
346 devopt = strstr (mnt->mnt_opts, "dev=");
349 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
350 me->me_dev = xatoi (devopt + 6);
352 me->me_dev = xatoi (devopt + 4);
355 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
357 /* Add to the linked list. */
359 mtail = &me->me_next;
362 if (endmntent (fp) == 0)
365 #endif /* MOUNTED_GETMNTENT1. */
367 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
372 entries = getmntinfo (&fsp, MNT_NOWAIT);
375 for (; entries-- > 0; fsp++)
377 char *fs_type = fsp_to_string (fsp);
379 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
380 me->me_devname = xstrdup (fsp->f_mntfromname);
381 me->me_mountdir = xstrdup (fsp->f_mntonname);
382 me->me_type = fs_type;
383 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
384 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
385 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
387 /* Add to the linked list. */
389 mtail = &me->me_next;
392 #endif /* MOUNTED_GETMNTINFO */
394 #ifdef MOUNTED_GETMNT /* Ultrix. */
401 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
404 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
405 me->me_devname = xstrdup (fsd.fd_req.devname);
406 me->me_mountdir = xstrdup (fsd.fd_req.path);
407 me->me_type = gt_names[fsd.fd_req.fstype];
408 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
409 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
410 me->me_dev = fsd.fd_req.dev;
412 /* Add to the linked list. */
414 mtail = &me->me_next;
419 #endif /* MOUNTED_GETMNT. */
421 #if defined (MOUNTED_NEXT_DEV) /* BeOS */
423 /* The next_dev() and fs_stat_dev() system calls give the list of
424 all filesystems, including the information returned by statvfs()
425 (fs type, total blocks, free blocks etc.), but without the mount
426 point. But on BeOS all filesystems except / are mounted in the
427 rootfs, directly under /.
428 The directory name of the mount point is often, but not always,
429 identical to the volume name of the device.
430 We therefore get the list of subdirectories of /, and the list
431 of all filesystems, and match the two lists. */
439 struct rootdir_entry *next;
441 struct rootdir_entry *rootdir_list;
442 struct rootdir_entry **rootdir_tail;
447 /* All volumes are mounted in the rootfs, directly under /. */
449 rootdir_tail = &rootdir_list;
450 dirp = opendir ("/");
455 while ((d = readdir (dirp)) != NULL)
460 if (strcmp (d->d_name, "..") == 0)
463 if (strcmp (d->d_name, ".") == 0)
464 name = xstrdup ("/");
467 name = xmalloc (1 + strlen (d->d_name) + 1);
469 strcpy (name + 1, d->d_name);
472 if (stat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
474 struct rootdir_entry *re;
476 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
478 re->dev = statbuf.st_dev;
479 re->ino = statbuf.st_ino;
481 /* Add to the linked list. */
483 rootdir_tail = &re->next;
490 *rootdir_tail = NULL;
492 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
493 if (fs_stat_dev (dev, &fi) >= 0)
495 /* Note: fi.dev == dev. */
496 struct rootdir_entry *re;
498 for (re = rootdir_list; re; re = re->next)
499 if (re->dev == fi.dev && re->ino == fi.root)
502 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
503 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
504 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
505 me->me_type = xstrdup (fi.fsh_name);
508 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
510 /* Add to the linked list. */
512 mtail = &me->me_next;
516 while (rootdir_list != NULL)
518 struct rootdir_entry *re = rootdir_list;
519 rootdir_list = re->next;
524 #endif /* MOUNTED_NEXT_DEV */
526 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
528 int numsys, counter, bufsize;
529 struct statfs *stats;
531 numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
535 bufsize = (1 + numsys) * sizeof (struct statfs);
536 stats = (struct statfs *)xmalloc (bufsize);
537 numsys = getfsstat (stats, bufsize, MNT_WAIT);
545 for (counter = 0; counter < numsys; counter++)
547 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
548 me->me_devname = xstrdup (stats[counter].f_mntfromname);
549 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
550 me->me_type = mnt_names[stats[counter].f_type];
551 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
552 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
553 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
555 /* Add to the linked list. */
557 mtail = &me->me_next;
562 #endif /* MOUNTED_GETFSSTAT */
564 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
567 char *table = "/etc/mnttab";
570 fp = fopen (table, "r");
574 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
576 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
577 # ifdef GETFSTYP /* SVR3. */
578 me->me_devname = xstrdup (mnt.mt_dev);
580 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
581 strcpy (me->me_devname, "/dev/");
582 strcpy (me->me_devname + 5, mnt.mt_dev);
584 me->me_mountdir = xstrdup (mnt.mt_filsys);
585 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
587 # ifdef GETFSTYP /* SVR3. */
591 char typebuf[FSTYPSZ];
593 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
594 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
595 me->me_type = xstrdup (typebuf);
598 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
599 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
601 /* Add to the linked list. */
603 mtail = &me->me_next;
608 int saved_errno = errno;
614 if (fclose (fp) == EOF)
617 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
619 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
621 struct mntent **mnttbl=getmnttbl(),**ent;
622 for (ent=mnttbl;*ent;ent++)
624 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
625 me->me_devname = xstrdup ( (*ent)->mt_resource);
626 me->me_mountdir = xstrdup( (*ent)->mt_directory);
627 me->me_type = xstrdup ((*ent)->mt_fstype);
628 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
629 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
630 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
632 /* Add to the linked list. */
634 mtail = &me->me_next;
640 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
643 char *table = MNTTAB;
648 # if defined F_RDLCK && defined F_SETLKW
649 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
650 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
651 for this file name, we should use their macro name instead.
652 (Why not just lock MNTTAB directly? We don't know.) */
654 # define MNTTAB_LOCK "/etc/.mnttab.lock"
656 lockfd = open (MNTTAB_LOCK, O_RDONLY);
660 flock.l_type = F_RDLCK;
661 flock.l_whence = SEEK_SET;
664 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
667 int saved_errno = errno;
673 else if (errno != ENOENT)
678 fp = fopen (table, "r");
683 while ((ret = getmntent (fp, &mnt)) == 0)
685 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
686 me->me_devname = xstrdup (mnt.mnt_special);
687 me->me_mountdir = xstrdup (mnt.mnt_mountp);
688 me->me_type = xstrdup (mnt.mnt_fstype);
689 me->me_dummy = MNT_IGNORE (&mnt) != 0;
690 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
691 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
693 /* Add to the linked list. */
695 mtail = &me->me_next;
698 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
701 if (0 <= lockfd && close (lockfd) != 0)
710 #endif /* MOUNTED_GETMNTENT2. */
712 #ifdef MOUNTED_VMOUNT /* AIX. */
715 char *entries, *thisent;
718 /* Ask how many bytes to allocate for the mounted filesystem info. */
719 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
720 entries = xmalloc (bufsize);
722 /* Get the list of mounted filesystems. */
723 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
725 for (thisent = entries; thisent < entries + bufsize;
726 thisent += vmp->vmt_length)
728 vmp = (struct vmount *) thisent;
729 me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
730 if (vmp->vmt_flags & MNT_REMOTE)
735 /* Prepend the remote pathname. */
736 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
737 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
738 me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
739 strcpy (me->me_devname, host);
740 strcat (me->me_devname, ":");
741 strcat (me->me_devname, path);
746 me->me_devname = xstrdup (thisent +
747 vmp->vmt_data[VMT_OBJECT].vmt_off);
749 me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
750 me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
751 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
752 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
754 /* Add to the linked list. */
756 mtail = &me->me_next;
760 #endif /* MOUNTED_VMOUNT. */
768 int saved_errno = errno;
773 me = mount_list->me_next;
774 free (mount_list->me_devname);
775 free (mount_list->me_mountdir);
776 /* FIXME: me_type is not always malloced. */