1 /* mountlist.c -- return a list of mounted file systems
2 Copyright (C) 1991, 1992, 1997-2004 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>
44 # include <sys/param.h>
47 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
49 # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
50 NGROUPS is used as an array dimension in ucred.h */
51 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
54 # include <sys/mount.h>
56 # if HAVE_SYS_FS_TYPES_H
57 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
59 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
60 # define FS_TYPE(Ent) ((Ent).f_fstypename)
62 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
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>
130 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
131 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
133 # define MNT_IGNORE(M) 0
136 #include "mountlist.h"
137 #include "unlocked-io.h"
140 # define SIZE_MAX ((size_t) -1)
143 #if MOUNTED_GETMNTINFO
145 # if ! HAVE_F_FSTYPENAME_IN_STATFS
147 fstype_to_string (short int t)
239 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
241 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
243 fsp_to_string (const struct statfs *fsp)
245 # if defined HAVE_F_FSTYPENAME_IN_STATFS
246 return (char *) (fsp->f_fstypename);
248 return fstype_to_string (fsp->f_type);
252 #endif /* MOUNTED_GETMNTINFO */
254 #ifdef MOUNTED_VMOUNT /* AIX. */
256 fstype_to_string (int t)
260 e = getvfsbytype (t);
261 if (!e || !e->vfsent_name)
264 return e->vfsent_name;
266 #endif /* MOUNTED_VMOUNT */
268 /* Return a list of the currently mounted file systems, or NULL on error.
269 Add each entry to the tail of the list so that they stay in order.
270 If NEED_FS_TYPE is true, ensure that the file system type fields in
271 the returned list are valid. Otherwise, they might not be. */
274 read_file_system_list (bool need_fs_type)
276 struct mount_entry *mount_list;
277 struct mount_entry *me;
278 struct mount_entry **mtail = &mount_list;
280 #ifdef MOUNTED_LISTMNTENT
282 struct tabmntent *mntlist, *p;
284 struct mount_entry *me;
286 /* the third and fourth arguments could be used to filter mounts,
287 but Crays doesn't seem to have any mounts that we want to
288 remove. Specifically, automount create normal NFS mounts.
291 if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
293 for (p = mntlist; p; p = p->next) {
295 me = xmalloc (sizeof *me);
296 me->me_devname = xstrdup (mnt->mnt_fsname);
297 me->me_mountdir = xstrdup (mnt->mnt_dir);
298 me->me_type = xstrdup (mnt->mnt_type);
299 me->me_type_malloced = 1;
300 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
301 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
304 mtail = &me->me_next;
306 freemntlist (mntlist);
310 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
313 char *table = MOUNTED;
317 fp = setmntent (table, "r");
321 while ((mnt = getmntent (fp)))
323 me = xmalloc (sizeof *me);
324 me->me_devname = xstrdup (mnt->mnt_fsname);
325 me->me_mountdir = xstrdup (mnt->mnt_dir);
326 me->me_type = xstrdup (mnt->mnt_type);
327 me->me_type_malloced = 1;
328 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
329 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
330 devopt = strstr (mnt->mnt_opts, "dev=");
332 me->me_dev = strtoul (devopt + 4, NULL, 16);
334 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
336 /* Add to the linked list. */
338 mtail = &me->me_next;
341 if (endmntent (fp) == 0)
344 #endif /* MOUNTED_GETMNTENT1. */
346 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
351 entries = getmntinfo (&fsp, MNT_NOWAIT);
354 for (; entries-- > 0; fsp++)
356 char *fs_type = fsp_to_string (fsp);
358 me = xmalloc (sizeof *me);
359 me->me_devname = xstrdup (fsp->f_mntfromname);
360 me->me_mountdir = xstrdup (fsp->f_mntonname);
361 me->me_type = fs_type;
362 me->me_type_malloced = 0;
363 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
364 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
365 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
367 /* Add to the linked list. */
369 mtail = &me->me_next;
372 #endif /* MOUNTED_GETMNTINFO */
374 #ifdef MOUNTED_GETMNT /* Ultrix. */
381 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
384 me = xmalloc (sizeof *me);
385 me->me_devname = xstrdup (fsd.fd_req.devname);
386 me->me_mountdir = xstrdup (fsd.fd_req.path);
387 me->me_type = gt_names[fsd.fd_req.fstype];
388 me->me_type_malloced = 0;
389 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
390 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
391 me->me_dev = fsd.fd_req.dev;
393 /* Add to the linked list. */
395 mtail = &me->me_next;
400 #endif /* MOUNTED_GETMNT. */
402 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
404 /* The next_dev() and fs_stat_dev() system calls give the list of
405 all file systems, including the information returned by statvfs()
406 (fs type, total blocks, free blocks etc.), but without the mount
407 point. But on BeOS all file systems except / are mounted in the
408 rootfs, directly under /.
409 The directory name of the mount point is often, but not always,
410 identical to the volume name of the device.
411 We therefore get the list of subdirectories of /, and the list
412 of all file systems, and match the two lists. */
420 struct rootdir_entry *next;
422 struct rootdir_entry *rootdir_list;
423 struct rootdir_entry **rootdir_tail;
428 /* All volumes are mounted in the rootfs, directly under /. */
430 rootdir_tail = &rootdir_list;
431 dirp = opendir ("/");
436 while ((d = readdir (dirp)) != NULL)
441 if (strcmp (d->d_name, "..") == 0)
444 if (strcmp (d->d_name, ".") == 0)
445 name = xstrdup ("/");
448 name = xmalloc (1 + strlen (d->d_name) + 1);
450 strcpy (name + 1, d->d_name);
453 if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
455 struct rootdir_entry *re = xmalloc (sizeof *re);
457 re->dev = statbuf.st_dev;
458 re->ino = statbuf.st_ino;
460 /* Add to the linked list. */
462 rootdir_tail = &re->next;
469 *rootdir_tail = NULL;
471 for (pos = 0; (dev = next_dev (&pos)) >= 0; )
472 if (fs_stat_dev (dev, &fi) >= 0)
474 /* Note: fi.dev == dev. */
475 struct rootdir_entry *re;
477 for (re = rootdir_list; re; re = re->next)
478 if (re->dev == fi.dev && re->ino == fi.root)
481 me = xmalloc (sizeof *me);
482 me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
483 me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
484 me->me_type = xstrdup (fi.fsh_name);
485 me->me_type_malloced = 1;
488 me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
490 /* Add to the linked list. */
492 mtail = &me->me_next;
496 while (rootdir_list != NULL)
498 struct rootdir_entry *re = rootdir_list;
499 rootdir_list = re->next;
504 #endif /* MOUNTED_FS_STAT_DEV */
506 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
510 struct statfs *stats;
512 numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
515 if (SIZE_MAX / sizeof *stats <= numsys)
518 bufsize = (1 + numsys) * sizeof *stats;
519 stats = xmalloc (bufsize);
520 numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
528 for (counter = 0; counter < numsys; counter++)
530 me = xmalloc (sizeof *me);
531 me->me_devname = xstrdup (stats[counter].f_mntfromname);
532 me->me_mountdir = xstrdup (stats[counter].f_mntonname);
533 me->me_type = xstrdup (FS_TYPE (stats[counter]));
534 me->me_type_malloced = 1;
535 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
536 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
537 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
539 /* Add to the linked list. */
541 mtail = &me->me_next;
546 #endif /* MOUNTED_GETFSSTAT */
548 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
551 char *table = "/etc/mnttab";
554 fp = fopen (table, "r");
558 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
560 me = xmalloc (sizeof *me);
561 # ifdef GETFSTYP /* SVR3. */
562 me->me_devname = xstrdup (mnt.mt_dev);
564 me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
565 strcpy (me->me_devname, "/dev/");
566 strcpy (me->me_devname + 5, mnt.mt_dev);
568 me->me_mountdir = xstrdup (mnt.mt_filsys);
569 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
571 me->me_type_malloced = 0;
572 # ifdef GETFSTYP /* SVR3. */
576 char typebuf[FSTYPSZ];
578 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
579 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
581 me->me_type = xstrdup (typebuf);
582 me->me_type_malloced = 1;
586 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
587 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
589 /* Add to the linked list. */
591 mtail = &me->me_next;
596 /* The last fread() call must have failed. */
597 int saved_errno = errno;
603 if (fclose (fp) == EOF)
606 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
608 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
610 struct mntent **mnttbl = getmnttbl (), **ent;
611 for (ent=mnttbl;*ent;ent++)
613 me = xmalloc (sizeof *me);
614 me->me_devname = xstrdup ( (*ent)->mt_resource);
615 me->me_mountdir = xstrdup ( (*ent)->mt_directory);
616 me->me_type = xstrdup ((*ent)->mt_fstype);
617 me->me_type_malloced = 1;
618 me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
619 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
620 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
622 /* Add to the linked list. */
624 mtail = &me->me_next;
630 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
633 char *table = MNTTAB;
638 # if defined F_RDLCK && defined F_SETLKW
639 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
640 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
641 for this file name, we should use their macro name instead.
642 (Why not just lock MNTTAB directly? We don't know.) */
644 # define MNTTAB_LOCK "/etc/.mnttab.lock"
646 lockfd = open (MNTTAB_LOCK, O_RDONLY);
650 flock.l_type = F_RDLCK;
651 flock.l_whence = SEEK_SET;
654 while (fcntl (lockfd, F_SETLKW, &flock) == -1)
657 int saved_errno = errno;
663 else if (errno != ENOENT)
668 fp = fopen (table, "r");
673 while ((ret = getmntent (fp, &mnt)) == 0)
675 me = xmalloc (sizeof *me);
676 me->me_devname = xstrdup (mnt.mnt_special);
677 me->me_mountdir = xstrdup (mnt.mnt_mountp);
678 me->me_type = xstrdup (mnt.mnt_fstype);
679 me->me_type_malloced = 1;
680 me->me_dummy = MNT_IGNORE (&mnt) != 0;
681 me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
682 me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
684 /* Add to the linked list. */
686 mtail = &me->me_next;
689 ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
692 if (0 <= lockfd && close (lockfd) != 0)
701 #endif /* MOUNTED_GETMNTENT2. */
703 #ifdef MOUNTED_VMOUNT /* AIX. */
706 char *entries, *thisent;
711 /* Ask how many bytes to allocate for the mounted file system info. */
712 if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
714 entries = xmalloc (bufsize);
716 /* Get the list of mounted file systems. */
717 n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
720 int saved_errno = errno;
726 for (i = 0, thisent = entries;
728 i++, thisent += vmp->vmt_length)
730 char *options, *ignore;
732 vmp = (struct vmount *) thisent;
733 me = xmalloc (sizeof *me);
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 me->me_type_malloced = 1;
756 options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
757 ignore = strstr (options, "ignore");
758 me->me_dummy = (ignore
759 && (ignore == options || ignore[-1] == ',')
760 && (ignore[sizeof "ignore" - 1] == ','
761 || ignore[sizeof "ignore" - 1] == '\0'));
762 me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
764 /* Add to the linked list. */
766 mtail = &me->me_next;
770 #endif /* MOUNTED_VMOUNT. */
778 int saved_errno = errno;
783 me = mount_list->me_next;
784 free (mount_list->me_devname);
785 free (mount_list->me_mountdir);
786 if (mount_list->me_type_malloced)
787 free (mount_list->me_type);