1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992, 1997-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)
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. */
68 # if !defined(MOUNTED)
69 # if defined(MNT_MNTTAB) /* HP-UX. */
70 # define MOUNTED MNT_MNTTAB
72 # if defined(MNTTABNAME) /* Dynix. */
73 # define MOUNTED MNTTABNAME
78 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
79 # include <sys/mount.h>
82 #ifdef MOUNTED_GETMNT /* Ultrix. */
83 # include <sys/mount.h>
84 # include <sys/fs_types.h>
87 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
92 #ifdef MOUNTED_FREAD /* SVR2. */
96 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
98 # include <sys/fstyp.h>
99 # include <sys/statfs.h>
102 #ifdef MOUNTED_LISTMNTENT
106 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
107 # include <sys/mnttab.h>
110 #ifdef MOUNTED_VMOUNT /* AIX. */
112 # include <sys/vfs.h>
116 /* So special that it's not worth putting this in autoconf. */
117 # undef MOUNTED_FREAD_FSTYP
118 # define MOUNTED_GETMNTTBL
121 #if HAVE_SYS_MNTENT_H
122 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
123 # include <sys/mntent.h>
126 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
127 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
129 # define MNT_IGNORE(M) 0
132 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
133 /* Return the value of the hexadecimal number represented by CP.
134 No prefix (like '0x') or suffix (like 'h') is expected to be
136 /* FIXME: this can overflow */
146 if (*cp
>= 'a' && *cp
<= 'f')
147 val
= val
* 16 + *cp
- 'a' + 10;
148 else if (*cp
>= 'A' && *cp
<= 'F')
149 val
= val
* 16 + *cp
- 'A' + 10;
150 else if (*cp
>= '0' && *cp
<= '9')
151 val
= val
* 16 + *cp
- '0';
158 #endif /* MOUNTED_GETMNTENT1. */
160 #if MOUNTED_GETMNTINFO
162 # if ! HAVE_F_FSTYPENAME_IN_STATFS
164 fstype_to_string (short t
)
256 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
258 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
260 fsp_to_string (const struct statfs
*fsp
)
262 # if defined HAVE_F_FSTYPENAME_IN_STATFS
263 return (char *) (fsp
->f_fstypename
);
265 return fstype_to_string (fsp
->f_type
);
269 #endif /* MOUNTED_GETMNTINFO */
271 #ifdef MOUNTED_VMOUNT /* AIX. */
273 fstype_to_string (int t
)
277 e
= getvfsbytype (t
);
278 if (!e
|| !e
->vfsent_name
)
281 return e
->vfsent_name
;
283 #endif /* MOUNTED_VMOUNT */
285 /* Return a list of the currently mounted filesystems, or NULL on error.
286 Add each entry to the tail of the list so that they stay in order.
287 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
288 the returned list are valid. Otherwise, they might not be. */
291 read_filesystem_list (int need_fs_type
)
293 struct mount_entry
*mount_list
;
294 struct mount_entry
*me
;
295 struct mount_entry
**mtail
= &mount_list
;
297 #ifdef MOUNTED_LISTMNTENT
299 struct tabmntent
*mntlist
, *p
;
301 struct mount_entry
*me
;
303 /* the third and fourth arguments could be used to filter mounts,
304 but Crays doesn't seem to have any mounts that we want to
305 remove. Specifically, automount create normal NFS mounts.
308 if(listmntent(&mntlist
, KMTAB
, NULL
, NULL
) < 0)
310 for (p
= mntlist
; p
; p
= p
->next
) {
312 me
= (struct mount_entry
*) xmalloc(sizeof (struct mount_entry
));
313 me
->me_devname
= xstrdup(mnt
->mnt_fsname
);
314 me
->me_mountdir
= xstrdup(mnt
->mnt_dir
);
315 me
->me_type
= xstrdup(mnt
->mnt_type
);
316 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
317 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
320 mtail
= &me
->me_next
;
322 freemntlist(mntlist
);
326 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
329 char *table
= MOUNTED
;
333 fp
= setmntent (table
, "r");
337 while ((mnt
= getmntent (fp
)))
339 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
340 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
341 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
342 me
->me_type
= xstrdup (mnt
->mnt_type
);
343 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
344 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
345 devopt
= strstr (mnt
->mnt_opts
, "dev=");
348 if (devopt
[4] == '0' && (devopt
[5] == 'x' || devopt
[5] == 'X'))
349 me
->me_dev
= xatoi (devopt
+ 6);
351 me
->me_dev
= xatoi (devopt
+ 4);
354 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
356 /* Add to the linked list. */
358 mtail
= &me
->me_next
;
361 if (endmntent (fp
) == 0)
364 #endif /* MOUNTED_GETMNTENT1. */
366 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
371 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
374 for (; entries
-- > 0; fsp
++)
376 char *fs_type
= fsp_to_string (fsp
);
378 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
379 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
380 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
381 me
->me_type
= fs_type
;
382 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
383 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
384 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
386 /* Add to the linked list. */
388 mtail
= &me
->me_next
;
391 #endif /* MOUNTED_GETMNTINFO */
393 #ifdef MOUNTED_GETMNT /* Ultrix. */
400 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
403 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
404 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
405 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
406 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
407 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
408 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
409 me
->me_dev
= fsd
.fd_req
.dev
;
411 /* Add to the linked list. */
413 mtail
= &me
->me_next
;
418 #endif /* MOUNTED_GETMNT. */
420 #if defined (MOUNTED_FS_STAT_DEV) /* BeOS */
422 /* The next_dev() and fs_stat_dev() system calls give the list of
423 all filesystems, including the information returned by statvfs()
424 (fs type, total blocks, free blocks etc.), but without the mount
425 point. But on BeOS all filesystems except / are mounted in the
426 rootfs, directly under /.
427 The directory name of the mount point is often, but not always,
428 identical to the volume name of the device.
429 We therefore get the list of subdirectories of /, and the list
430 of all filesystems, and match the two lists. */
438 struct rootdir_entry
*next
;
440 struct rootdir_entry
*rootdir_list
;
441 struct rootdir_entry
**rootdir_tail
;
446 /* All volumes are mounted in the rootfs, directly under /. */
448 rootdir_tail
= &rootdir_list
;
449 dirp
= opendir ("/");
454 while ((d
= readdir (dirp
)) != NULL
)
459 if (strcmp (d
->d_name
, "..") == 0)
462 if (strcmp (d
->d_name
, ".") == 0)
463 name
= xstrdup ("/");
466 name
= xmalloc (1 + strlen (d
->d_name
) + 1);
468 strcpy (name
+ 1, d
->d_name
);
471 if (lstat (name
, &statbuf
) >= 0 && S_ISDIR (statbuf
.st_mode
))
473 struct rootdir_entry
*re
;
475 re
= (struct rootdir_entry
*) xmalloc (sizeof (struct rootdir_entry
));
477 re
->dev
= statbuf
.st_dev
;
478 re
->ino
= statbuf
.st_ino
;
480 /* Add to the linked list. */
482 rootdir_tail
= &re
->next
;
489 *rootdir_tail
= NULL
;
491 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
492 if (fs_stat_dev (dev
, &fi
) >= 0)
494 /* Note: fi.dev == dev. */
495 struct rootdir_entry
*re
;
497 for (re
= rootdir_list
; re
; re
= re
->next
)
498 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
501 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
502 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
503 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
504 me
->me_type
= xstrdup (fi
.fsh_name
);
507 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
509 /* Add to the linked list. */
511 mtail
= &me
->me_next
;
515 while (rootdir_list
!= NULL
)
517 struct rootdir_entry
*re
= rootdir_list
;
518 rootdir_list
= re
->next
;
523 #endif /* MOUNTED_FS_STAT_DEV */
525 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
527 int numsys
, counter
, bufsize
;
528 struct statfs
*stats
;
530 numsys
= getfsstat ((struct statfs
*)0, 0L, MNT_WAIT
);
534 bufsize
= (1 + numsys
) * sizeof (struct statfs
);
535 stats
= (struct statfs
*)xmalloc (bufsize
);
536 numsys
= getfsstat (stats
, bufsize
, MNT_WAIT
);
544 for (counter
= 0; counter
< numsys
; counter
++)
546 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
547 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
548 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
549 me
->me_type
= mnt_names
[stats
[counter
].f_type
];
550 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
551 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
552 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
554 /* Add to the linked list. */
556 mtail
= &me
->me_next
;
561 #endif /* MOUNTED_GETFSSTAT */
563 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
566 char *table
= "/etc/mnttab";
569 fp
= fopen (table
, "r");
573 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
575 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
576 # ifdef GETFSTYP /* SVR3. */
577 me
->me_devname
= xstrdup (mnt
.mt_dev
);
579 me
->me_devname
= xmalloc (strlen (mnt
.mt_dev
) + 6);
580 strcpy (me
->me_devname
, "/dev/");
581 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
583 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
584 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
586 # ifdef GETFSTYP /* SVR3. */
590 char typebuf
[FSTYPSZ
];
592 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
593 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
594 me
->me_type
= xstrdup (typebuf
);
597 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
598 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
600 /* Add to the linked list. */
602 mtail
= &me
->me_next
;
607 int saved_errno
= errno
;
613 if (fclose (fp
) == EOF
)
616 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
618 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
620 struct mntent
**mnttbl
=getmnttbl(),**ent
;
621 for (ent
=mnttbl
;*ent
;ent
++)
623 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
624 me
->me_devname
= xstrdup ( (*ent
)->mt_resource
);
625 me
->me_mountdir
= xstrdup( (*ent
)->mt_directory
);
626 me
->me_type
= xstrdup ((*ent
)->mt_fstype
);
627 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
628 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
629 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
631 /* Add to the linked list. */
633 mtail
= &me
->me_next
;
639 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
642 char *table
= MNTTAB
;
647 # if defined F_RDLCK && defined F_SETLKW
648 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
649 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
650 for this file name, we should use their macro name instead.
651 (Why not just lock MNTTAB directly? We don't know.) */
653 # define MNTTAB_LOCK "/etc/.mnttab.lock"
655 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
659 flock
.l_type
= F_RDLCK
;
660 flock
.l_whence
= SEEK_SET
;
663 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
666 int saved_errno
= errno
;
672 else if (errno
!= ENOENT
)
677 fp
= fopen (table
, "r");
682 while ((ret
= getmntent (fp
, &mnt
)) == 0)
684 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
685 me
->me_devname
= xstrdup (mnt
.mnt_special
);
686 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
687 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
688 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
689 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
690 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
692 /* Add to the linked list. */
694 mtail
= &me
->me_next
;
697 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
700 if (0 <= lockfd
&& close (lockfd
) != 0)
709 #endif /* MOUNTED_GETMNTENT2. */
711 #ifdef MOUNTED_VMOUNT /* AIX. */
714 char *entries
, *thisent
;
717 /* Ask how many bytes to allocate for the mounted filesystem info. */
718 mntctl (MCTL_QUERY
, sizeof bufsize
, (struct vmount
*) &bufsize
);
719 entries
= xmalloc (bufsize
);
721 /* Get the list of mounted filesystems. */
722 mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
724 for (thisent
= entries
; thisent
< entries
+ bufsize
;
725 thisent
+= vmp
->vmt_length
)
727 char *options
, *ignore
;
729 vmp
= (struct vmount
*) thisent
;
730 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
731 if (vmp
->vmt_flags
& MNT_REMOTE
)
736 /* Prepend the remote pathname. */
737 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
738 path
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
739 me
->me_devname
= xmalloc (strlen (host
) + strlen (path
) + 2);
740 strcpy (me
->me_devname
, host
);
741 strcat (me
->me_devname
, ":");
742 strcat (me
->me_devname
, path
);
747 me
->me_devname
= xstrdup (thisent
+
748 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
750 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
751 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
752 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
753 ignore
= strstr (options
, "ignore");
754 me
->me_dummy
= (ignore
755 && (ignore
== options
|| ignore
[-1] == ',')
756 && (ignore
[sizeof "ignore" - 1] == ','
757 || ignore
[sizeof "ignore" - 1] == '\0'));
758 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
760 /* Add to the linked list. */
762 mtail
= &me
->me_next
;
766 #endif /* MOUNTED_VMOUNT. */
774 int saved_errno
= errno
;
779 me
= mount_list
->me_next
;
780 free (mount_list
->me_devname
);
781 free (mount_list
->me_mountdir
);
782 /* FIXME: me_type is not always malloced. */