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>
31 #if defined STDC_HEADERS || defined HAVE_STRING_H
56 # include <sys/param.h>
59 #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
61 # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
64 # include <sys/mount.h>
66 # if HAVE_SYS_FS_TYPES_H
67 # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
69 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
70 # define FS_TYPE(Ent) ((Ent).f_fstypename)
72 # define FS_TYPE(Ent) mnt_names[(Ent).f_type]
74 #endif /* MOUNTED_GETFSSTAT */
76 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
79 # if defined _PATH_MOUNTED /* GNU libc */
80 # define MOUNTED _PATH_MOUNTED
82 # if defined MNT_MNTTAB /* HP-UX. */
83 # define MOUNTED MNT_MNTTAB
85 # if defined MNTTABNAME /* Dynix. */
86 # define MOUNTED MNTTABNAME
91 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
92 # include <sys/mount.h>
95 #ifdef MOUNTED_GETMNT /* Ultrix. */
96 # include <sys/mount.h>
97 # include <sys/fs_types.h>
100 #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
101 # include <fs_info.h>
105 #ifdef MOUNTED_FREAD /* SVR2. */
109 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
111 # include <sys/fstyp.h>
112 # include <sys/statfs.h>
115 #ifdef MOUNTED_LISTMNTENT
119 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
120 # include <sys/mnttab.h>
123 #ifdef MOUNTED_VMOUNT /* AIX. */
125 # include <sys/vfs.h>
129 /* So special that it's not worth putting this in autoconf. */
130 # undef MOUNTED_FREAD_FSTYP
131 # define MOUNTED_GETMNTTBL
134 #if HAVE_SYS_MNTENT_H
135 /* This is to get MNTOPT_IGNORE on e.g. SVR4. */
136 # include <sys/mntent.h>
139 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
140 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
142 # define MNT_IGNORE(M) 0
145 #include "mountlist.h"
146 #include "unlocked-io.h"
148 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
149 /* Return the value of the hexadecimal number represented by CP.
150 No prefix (like '0x') or suffix (like 'h') is expected to be
152 /* FIXME: this can overflow */
162 if (*cp
>= 'a' && *cp
<= 'f')
163 val
= val
* 16 + *cp
- 'a' + 10;
164 else if (*cp
>= 'A' && *cp
<= 'F')
165 val
= val
* 16 + *cp
- 'A' + 10;
166 else if (*cp
>= '0' && *cp
<= '9')
167 val
= val
* 16 + *cp
- '0';
174 #endif /* MOUNTED_GETMNTENT1. */
176 #if MOUNTED_GETMNTINFO
178 # if ! HAVE_F_FSTYPENAME_IN_STATFS
180 fstype_to_string (short t
)
272 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
274 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
276 fsp_to_string (const struct statfs
*fsp
)
278 # if defined HAVE_F_FSTYPENAME_IN_STATFS
279 return (char *) (fsp
->f_fstypename
);
281 return fstype_to_string (fsp
->f_type
);
285 #endif /* MOUNTED_GETMNTINFO */
287 #ifdef MOUNTED_VMOUNT /* AIX. */
289 fstype_to_string (int t
)
293 e
= getvfsbytype (t
);
294 if (!e
|| !e
->vfsent_name
)
297 return e
->vfsent_name
;
299 #endif /* MOUNTED_VMOUNT */
301 /* Return a list of the currently mounted filesystems, or NULL on error.
302 Add each entry to the tail of the list so that they stay in order.
303 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
304 the returned list are valid. Otherwise, they might not be. */
307 read_filesystem_list (int need_fs_type
)
309 struct mount_entry
*mount_list
;
310 struct mount_entry
*me
;
311 struct mount_entry
**mtail
= &mount_list
;
313 #ifdef MOUNTED_LISTMNTENT
315 struct tabmntent
*mntlist
, *p
;
317 struct mount_entry
*me
;
319 /* the third and fourth arguments could be used to filter mounts,
320 but Crays doesn't seem to have any mounts that we want to
321 remove. Specifically, automount create normal NFS mounts.
324 if(listmntent(&mntlist
, KMTAB
, NULL
, NULL
) < 0)
326 for (p
= mntlist
; p
; p
= p
->next
) {
328 me
= (struct mount_entry
*) xmalloc(sizeof (struct mount_entry
));
329 me
->me_devname
= xstrdup(mnt
->mnt_fsname
);
330 me
->me_mountdir
= xstrdup(mnt
->mnt_dir
);
331 me
->me_type
= xstrdup(mnt
->mnt_type
);
332 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
333 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
336 mtail
= &me
->me_next
;
338 freemntlist(mntlist
);
342 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
345 char *table
= MOUNTED
;
349 fp
= setmntent (table
, "r");
353 while ((mnt
= getmntent (fp
)))
355 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
356 me
->me_devname
= xstrdup (mnt
->mnt_fsname
);
357 me
->me_mountdir
= xstrdup (mnt
->mnt_dir
);
358 me
->me_type
= xstrdup (mnt
->mnt_type
);
359 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
360 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
361 devopt
= strstr (mnt
->mnt_opts
, "dev=");
364 if (devopt
[4] == '0' && (devopt
[5] == 'x' || devopt
[5] == 'X'))
365 me
->me_dev
= xatoi (devopt
+ 6);
367 me
->me_dev
= xatoi (devopt
+ 4);
370 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
372 /* Add to the linked list. */
374 mtail
= &me
->me_next
;
377 if (endmntent (fp
) == 0)
380 #endif /* MOUNTED_GETMNTENT1. */
382 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
387 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
390 for (; entries
-- > 0; fsp
++)
392 char *fs_type
= fsp_to_string (fsp
);
394 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
395 me
->me_devname
= xstrdup (fsp
->f_mntfromname
);
396 me
->me_mountdir
= xstrdup (fsp
->f_mntonname
);
397 me
->me_type
= fs_type
;
398 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
399 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
400 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
402 /* Add to the linked list. */
404 mtail
= &me
->me_next
;
407 #endif /* MOUNTED_GETMNTINFO */
409 #ifdef MOUNTED_GETMNT /* Ultrix. */
416 0 < (val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
419 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
420 me
->me_devname
= xstrdup (fsd
.fd_req
.devname
);
421 me
->me_mountdir
= xstrdup (fsd
.fd_req
.path
);
422 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
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
;
491 re
= (struct rootdir_entry
*) xmalloc (sizeof (struct rootdir_entry
));
493 re
->dev
= statbuf
.st_dev
;
494 re
->ino
= statbuf
.st_ino
;
496 /* Add to the linked list. */
498 rootdir_tail
= &re
->next
;
505 *rootdir_tail
= NULL
;
507 for (pos
= 0; (dev
= next_dev (&pos
)) >= 0; )
508 if (fs_stat_dev (dev
, &fi
) >= 0)
510 /* Note: fi.dev == dev. */
511 struct rootdir_entry
*re
;
513 for (re
= rootdir_list
; re
; re
= re
->next
)
514 if (re
->dev
== fi
.dev
&& re
->ino
== fi
.root
)
517 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
518 me
->me_devname
= xstrdup (fi
.device_name
[0] != '\0' ? fi
.device_name
: fi
.fsh_name
);
519 me
->me_mountdir
= xstrdup (re
!= NULL
? re
->name
: fi
.fsh_name
);
520 me
->me_type
= xstrdup (fi
.fsh_name
);
523 me
->me_remote
= (fi
.flags
& B_FS_IS_SHARED
) != 0;
525 /* Add to the linked list. */
527 mtail
= &me
->me_next
;
531 while (rootdir_list
!= NULL
)
533 struct rootdir_entry
*re
= rootdir_list
;
534 rootdir_list
= re
->next
;
539 #endif /* MOUNTED_FS_STAT_DEV */
541 #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
543 int numsys
, counter
, bufsize
;
544 struct statfs
*stats
;
546 numsys
= getfsstat ((struct statfs
*)0, 0L, MNT_WAIT
);
550 bufsize
= (1 + numsys
) * sizeof (struct statfs
);
551 stats
= (struct statfs
*)xmalloc (bufsize
);
552 numsys
= getfsstat (stats
, bufsize
, MNT_WAIT
);
560 for (counter
= 0; counter
< numsys
; counter
++)
562 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
563 me
->me_devname
= xstrdup (stats
[counter
].f_mntfromname
);
564 me
->me_mountdir
= xstrdup (stats
[counter
].f_mntonname
);
565 me
->me_type
= xstrdup (FS_TYPE (stats
[counter
]));
566 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
567 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
568 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
570 /* Add to the linked list. */
572 mtail
= &me
->me_next
;
577 #endif /* MOUNTED_GETFSSTAT */
579 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
582 char *table
= "/etc/mnttab";
585 fp
= fopen (table
, "r");
589 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0)
591 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
592 # ifdef GETFSTYP /* SVR3. */
593 me
->me_devname
= xstrdup (mnt
.mt_dev
);
595 me
->me_devname
= xmalloc (strlen (mnt
.mt_dev
) + 6);
596 strcpy (me
->me_devname
, "/dev/");
597 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
599 me
->me_mountdir
= xstrdup (mnt
.mt_filsys
);
600 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
602 # ifdef GETFSTYP /* SVR3. */
606 char typebuf
[FSTYPSZ
];
608 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
609 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
610 me
->me_type
= xstrdup (typebuf
);
613 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
614 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
616 /* Add to the linked list. */
618 mtail
= &me
->me_next
;
623 int saved_errno
= errno
;
629 if (fclose (fp
) == EOF
)
632 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
634 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
636 struct mntent
**mnttbl
=getmnttbl(),**ent
;
637 for (ent
=mnttbl
;*ent
;ent
++)
639 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
640 me
->me_devname
= xstrdup ( (*ent
)->mt_resource
);
641 me
->me_mountdir
= xstrdup( (*ent
)->mt_directory
);
642 me
->me_type
= xstrdup ((*ent
)->mt_fstype
);
643 me
->me_dummy
= ME_DUMMY (me
->me_devname
, me
->me_type
);
644 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
645 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
647 /* Add to the linked list. */
649 mtail
= &me
->me_next
;
655 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
658 char *table
= MNTTAB
;
663 # if defined F_RDLCK && defined F_SETLKW
664 /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
665 e.g. Solaris 2.6. If the SVR4 folks ever define a macro
666 for this file name, we should use their macro name instead.
667 (Why not just lock MNTTAB directly? We don't know.) */
669 # define MNTTAB_LOCK "/etc/.mnttab.lock"
671 lockfd
= open (MNTTAB_LOCK
, O_RDONLY
);
675 flock
.l_type
= F_RDLCK
;
676 flock
.l_whence
= SEEK_SET
;
679 while (fcntl (lockfd
, F_SETLKW
, &flock
) == -1)
682 int saved_errno
= errno
;
688 else if (errno
!= ENOENT
)
693 fp
= fopen (table
, "r");
698 while ((ret
= getmntent (fp
, &mnt
)) == 0)
700 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
701 me
->me_devname
= xstrdup (mnt
.mnt_special
);
702 me
->me_mountdir
= xstrdup (mnt
.mnt_mountp
);
703 me
->me_type
= xstrdup (mnt
.mnt_fstype
);
704 me
->me_dummy
= MNT_IGNORE (&mnt
) != 0;
705 me
->me_remote
= ME_REMOTE (me
->me_devname
, me
->me_type
);
706 me
->me_dev
= (dev_t
) -1; /* Magic; means not known yet. */
708 /* Add to the linked list. */
710 mtail
= &me
->me_next
;
713 ret
= fclose (fp
) == EOF
? errno
: 0 < ret
? 0 : -1;
716 if (0 <= lockfd
&& close (lockfd
) != 0)
725 #endif /* MOUNTED_GETMNTENT2. */
727 #ifdef MOUNTED_VMOUNT /* AIX. */
730 char *entries
, *thisent
;
733 /* Ask how many bytes to allocate for the mounted filesystem info. */
734 mntctl (MCTL_QUERY
, sizeof bufsize
, (struct vmount
*) &bufsize
);
735 entries
= xmalloc (bufsize
);
737 /* Get the list of mounted filesystems. */
738 mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
740 for (thisent
= entries
; thisent
< entries
+ bufsize
;
741 thisent
+= vmp
->vmt_length
)
743 char *options
, *ignore
;
745 vmp
= (struct vmount
*) thisent
;
746 me
= (struct mount_entry
*) xmalloc (sizeof (struct mount_entry
));
747 if (vmp
->vmt_flags
& MNT_REMOTE
)
752 /* Prepend the remote pathname. */
753 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
754 path
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
755 me
->me_devname
= xmalloc (strlen (host
) + strlen (path
) + 2);
756 strcpy (me
->me_devname
, host
);
757 strcat (me
->me_devname
, ":");
758 strcat (me
->me_devname
, path
);
763 me
->me_devname
= xstrdup (thisent
+
764 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
766 me
->me_mountdir
= xstrdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
767 me
->me_type
= xstrdup (fstype_to_string (vmp
->vmt_gfstype
));
768 options
= thisent
+ vmp
->vmt_data
[VMT_ARGS
].vmt_off
;
769 ignore
= strstr (options
, "ignore");
770 me
->me_dummy
= (ignore
771 && (ignore
== options
|| ignore
[-1] == ',')
772 && (ignore
[sizeof "ignore" - 1] == ','
773 || ignore
[sizeof "ignore" - 1] == '\0'));
774 me
->me_dev
= (dev_t
) -1; /* vmt_fsid might be the info we want. */
776 /* Add to the linked list. */
778 mtail
= &me
->me_next
;
782 #endif /* MOUNTED_VMOUNT. */
790 int saved_errno
= errno
;
795 me
= mount_list
->me_next
;
796 free (mount_list
->me_devname
);
797 free (mount_list
->me_mountdir
);
798 /* FIXME: me_type is not always malloced. */