1
/* mountlist.c -- return a list of mounted file systems
3
Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4
2004, 2005, 2006, 2007 Free Software Foundation, Inc.
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, see <http://www.gnu.org/licenses/>.
20
// This file is not used on some platforms, so don't do anything for them
21
#if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__))
23
// We don't use autoconf and all that in grafx2, so let's do the config here ...
24
#if defined(__macosx__) || defined(__FreeBSD__) // MacOS X is POSIX compliant
25
#define MOUNTED_GETMNTINFO
26
#elif defined(__BEOS__) || defined(__HAIKU__)
27
#define MOUNTED_FS_STAT_DEV
28
#elif defined(__SKYOS__)
29
#warning "Your platform is missing some specific code here ! please check and fix :)"
31
#define MOUNTED_GETMNTENT1
33
// --- END GRAFX2 CUSTOM CONFIG ---
35
#include "mountlist.h"
49
# include <sys/param.h>
52
#if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */
54
# include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
55
NGROUPS is used as an array dimension in ucred.h */
56
# include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
59
# include <sys/mount.h>
61
# if HAVE_SYS_FS_TYPES_H
62
# include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
64
# if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
65
# define FS_TYPE(Ent) ((Ent).f_fstypename)
67
# define FS_TYPE(Ent) mnt_names[(Ent).f_type]
69
#endif /* MOUNTED_GETFSSTAT */
71
#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
74
# if defined _PATH_MOUNTED /* GNU libc */
75
# define MOUNTED _PATH_MOUNTED
77
# if defined MNT_MNTTAB /* HP-UX. */
78
# define MOUNTED MNT_MNTTAB
80
# if defined MNTTABNAME /* Dynix. */
81
# define MOUNTED MNTTABNAME
86
#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
87
# include <sys/mount.h>
90
#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
91
# include <sys/statvfs.h>
94
#ifdef MOUNTED_GETMNT /* Ultrix. */
95
# include <sys/mount.h>
96
# include <sys/fs_types.h>
99
#ifdef MOUNTED_FS_STAT_DEV /* BeOS. */
100
# include <fs_info.h>
104
#ifdef MOUNTED_FREAD /* SVR2. */
108
#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
110
# include <sys/fstyp.h>
111
# include <sys/statfs.h>
114
#ifdef MOUNTED_LISTMNTENT
118
#ifdef MOUNTED_GETMNTENT2 /* SVR4. */
119
# include <sys/mnttab.h>
122
#ifdef MOUNTED_VMOUNT /* AIX. */
124
# include <sys/vfs.h>
128
/* So special that it's not worth putting this in autoconf. */
129
# undef MOUNTED_FREAD_FSTYP
130
# define MOUNTED_GETMNTTBL
133
#if HAVE_SYS_MNTENT_H
134
/* This is to get MNTOPT_IGNORE on e.g. SVR4. */
135
# 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
146
# include "unlocked-io.h"
150
# define SIZE_MAX ((size_t) -1)
153
/* The results of open() in this file are not used with fchdir,
154
therefore save some unnecessary work in fchdir.c. */
158
/* The results of opendir() in this file are not used with dirfd and fchdir,
159
therefore save some unnecessary work in fchdir.c. */
163
// gcc2 under haiku and beos don't like these macros for some reason.
164
// As they are not used there anyways, we remove them and everyone is happy.
165
#if !defined(__HAIKU__) && !defined(__BEOS__)
167
# define ME_DUMMY(Fs_name, Fs_type) \
168
(strcmp (Fs_type, "autofs") == 0 \
169
|| strcmp (Fs_type, "none") == 0 \
170
|| strcmp (Fs_type, "proc") == 0 \
171
|| strcmp (Fs_type, "subfs") == 0 \
172
|| strcmp (Fs_type, "sysfs") == 0 \
173
|| strcmp (Fs_type, "usbfs") == 0 \
174
|| strcmp (Fs_type, "devpts") == 0 \
175
|| strcmp (Fs_type, "tmpfs") == 0 \
176
/* for NetBSD 3.0 */ \
177
|| strcmp (Fs_type, "kernfs") == 0 \
179
|| strcmp (Fs_type, "ignore") == 0 \
181
|| strcmp (Fs_type, "devfs") == 0 \
182
|| strcmp (Fs_type, "fdesc") == 0 \
183
|| strcmp (Fs_type, "nfs") == 0 \
184
|| strcmp (Fs_type, "volfs") == 0)
188
/* A file system is `remote' if its Fs_name contains a `:'
189
or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */
190
# define ME_REMOTE(Fs_name, Fs_type) \
191
(strchr (Fs_name, ':') != NULL \
192
|| ((Fs_name)[0] == '/' \
193
&& (Fs_name)[1] == '/' \
194
&& (strcmp (Fs_type, "smbfs") == 0 \
195
|| strcmp (Fs_type, "cifs") == 0)))
197
#endif // HAIKU / BEOS
199
#ifdef MOUNTED_GETMNTINFO
201
# if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
203
fstype_to_string (short int t)
298
fsp_to_string (const struct statfs *fsp)
300
# if HAVE_STRUCT_STATFS_F_FSTYPENAME
301
return (char *) (fsp->f_fstypename);
303
return fstype_to_string (fsp->f_type);
307
#endif /* MOUNTED_GETMNTINFO */
309
#ifdef MOUNTED_VMOUNT /* AIX. */
311
fstype_to_string (int t)
315
e = getvfsbytype (t);
316
if (!e || !e->vfsent_name)
319
return e->vfsent_name;
321
#endif /* MOUNTED_VMOUNT */
324
#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
326
/* Return the device number from MOUNT_OPTIONS, if possible.
327
Otherwise return (dev_t) -1. */
330
dev_from_mount_options (char const *mount_options)
332
/* GNU/Linux allows file system implementations to define their own
333
meaning for "dev=" mount options, so don't trust the meaning
337
static char const dev_pattern[] = ",dev=";
338
char const *devopt = strstr (mount_options, dev_pattern);
342
char const *optval = devopt + sizeof dev_pattern - 1;
344
unsigned long int dev;
346
dev = strtoul (optval, &optvalend, 16);
347
if (optval != optvalend
348
&& (*optvalend == '\0' || *optvalend == ',')
349
&& ! (dev == ULONG_MAX && errno == ERANGE)
350
&& dev == (dev_t) dev)
361
/* Return a list of the currently mounted file systems, or NULL on error.
362
Add each entry to the tail of the list so that they stay in order.
363
If NEED_FS_TYPE is true, ensure that the file system type fields in
364
the returned list are valid. Otherwise, they might not be. */
367
read_file_system_list (bool need_fs_type)
369
struct mount_entry *mount_list;
370
struct mount_entry *me;
371
struct mount_entry **mtail = &mount_list;
373
#ifdef MOUNTED_LISTMNTENT
375
struct tabmntent *mntlist, *p;
377
struct mount_entry *me;
379
/* the third and fourth arguments could be used to filter mounts,
380
but Crays doesn't seem to have any mounts that we want to
381
remove. Specifically, automount create normal NFS mounts.
384
if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
386
for (p = mntlist; p; p = p->next) {
388
me = xmalloc (sizeof *me);
389
me->me_devname = xstrdup (mnt->mnt_fsname);
390
me->me_mountdir = xstrdup (mnt->mnt_dir);
391
me->me_type = xstrdup (mnt->mnt_type);
392
me->me_type_malloced = 1;
393
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
394
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
397
mtail = &me->me_next;
399
freemntlist (mntlist);
403
#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
406
char *table = MOUNTED;
409
fp = setmntent (table, "r");
413
while ((mnt = getmntent (fp)))
415
me = malloc (sizeof *me);
416
me->me_devname = strdup (mnt->mnt_fsname);
417
me->me_mountdir = strdup (mnt->mnt_dir);
418
me->me_type = strdup (mnt->mnt_type);
419
me->me_type_malloced = 1;
420
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
421
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
422
me->me_dev = dev_from_mount_options (mnt->mnt_opts);
424
/* Add to the linked list. */
426
mtail = &me->me_next;
429
if (endmntent (fp) == 0)
432
#endif /* MOUNTED_GETMNTENT1. */
434
#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
439
entries = getmntinfo (&fsp, MNT_NOWAIT);
442
for (; entries-- > 0; fsp++)
444
me = malloc (sizeof *me);
445
me->me_devname = strdup (fsp->f_mntfromname);
446
me->me_mountdir = strdup (fsp->f_mntonname);
447
#if defined(__macosx__)
448
me->me_type = fsp->f_fstypename;
450
me->me_type = fsp->fs_typename;
452
me->me_type_malloced = 0;
453
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
454
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
455
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
457
/* Add to the linked list. */
459
mtail = &me->me_next;
462
#endif /* MOUNTED_GETMNTINFO */
464
#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
469
entries = getmntinfo (&fsp, MNT_NOWAIT);
472
for (; entries-- > 0; fsp++)
474
me = xmalloc (sizeof *me);
475
me->me_devname = xstrdup (fsp->f_mntfromname);
476
me->me_mountdir = xstrdup (fsp->f_mntonname);
477
me->me_type = xstrdup (fsp->f_fstypename);
478
me->me_type_malloced = 1;
479
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
480
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
481
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
483
/* Add to the linked list. */
485
mtail = &me->me_next;
488
#endif /* MOUNTED_GETMNTINFO2 */
490
#ifdef MOUNTED_GETMNT /* Ultrix. */
497
0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
500
me = xmalloc (sizeof *me);
501
me->me_devname = xstrdup (fsd.fd_req.devname);
502
me->me_mountdir = xstrdup (fsd.fd_req.path);
503
me->me_type = gt_names[fsd.fd_req.fstype];
504
me->me_type_malloced = 0;
505
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
506
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
507
me->me_dev = fsd.fd_req.dev;
509
/* Add to the linked list. */
511
mtail = &me->me_next;
516
#endif /* MOUNTED_GETMNT. */
518
#if defined MOUNTED_FS_STAT_DEV /* BeOS */
520
/* The next_dev() and fs_stat_dev() system calls give the list of
521
all file systems, including the information returned by statvfs()
522
(fs type, total blocks, free blocks etc.), but without the mount
523
point. But on BeOS all file systems except / are mounted in the
524
rootfs, directly under /.
525
The directory name of the mount point is often, but not always,
526
identical to the volume name of the device.
527
We therefore get the list of subdirectories of /, and the list
528
of all file systems, and match the two lists. */
536
struct rootdir_entry *next;
538
struct rootdir_entry *rootdir_list;
539
struct rootdir_entry **rootdir_tail;
544
/* All volumes are mounted in the rootfs, directly under /. */
546
rootdir_tail = &rootdir_list;
547
dirp = opendir ("/");
552
while ((d = readdir (dirp)) != NULL)
557
if (strcmp (d->d_name, "..") == 0)
560
if (strcmp (d->d_name, ".") == 0)
564
name = malloc (1 + strlen (d->d_name) + 1);
566
strcpy (name + 1, d->d_name);
569
if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
571
struct rootdir_entry *re = malloc (sizeof *re);
573
re->dev = statbuf.st_dev;
574
re->ino = statbuf.st_ino;
576
/* Add to the linked list. */
578
rootdir_tail = &re->next;
585
*rootdir_tail = NULL;
587
for (pos = 0; (dev = next_dev (&pos)) >= 0; )
588
if (fs_stat_dev (dev, &fi) >= 0)
590
/* Note: fi.dev == dev. */
591
struct rootdir_entry *re;
593
for (re = rootdir_list; re; re = re->next)
594
if (re->dev == fi.dev && re->ino == fi.root)
597
me = malloc (sizeof *me);
598
me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
599
me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name);
600
me->me_type = strdup (fi.fsh_name);
601
me->me_type_malloced = 1;
604
me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
606
/* Add to the linked list. */
608
mtail = &me->me_next;
612
while (rootdir_list != NULL)
614
struct rootdir_entry *re = rootdir_list;
615
rootdir_list = re->next;
620
#endif /* MOUNTED_FS_STAT_DEV */
622
#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
626
struct statfs *stats;
628
numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
631
if (SIZE_MAX / sizeof *stats <= numsys)
634
bufsize = (1 + numsys) * sizeof *stats;
635
stats = xmalloc (bufsize);
636
numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
644
for (counter = 0; counter < numsys; counter++)
646
me = xmalloc (sizeof *me);
647
me->me_devname = xstrdup (stats[counter].f_mntfromname);
648
me->me_mountdir = xstrdup (stats[counter].f_mntonname);
649
me->me_type = xstrdup (FS_TYPE (stats[counter]));
650
me->me_type_malloced = 1;
651
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
652
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
653
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
655
/* Add to the linked list. */
657
mtail = &me->me_next;
662
#endif /* MOUNTED_GETFSSTAT */
664
#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */
667
char *table = "/etc/mnttab";
670
fp = fopen (table, "r");
674
while (fread (&mnt, sizeof mnt, 1, fp) > 0)
676
me = xmalloc (sizeof *me);
677
# ifdef GETFSTYP /* SVR3. */
678
me->me_devname = xstrdup (mnt.mt_dev);
680
me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
681
strcpy (me->me_devname, "/dev/");
682
strcpy (me->me_devname + 5, mnt.mt_dev);
684
me->me_mountdir = xstrdup (mnt.mt_filsys);
685
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
687
me->me_type_malloced = 0;
688
# ifdef GETFSTYP /* SVR3. */
692
char typebuf[FSTYPSZ];
694
if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
695
&& sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
697
me->me_type = xstrdup (typebuf);
698
me->me_type_malloced = 1;
702
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
703
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
705
/* Add to the linked list. */
707
mtail = &me->me_next;
712
/* The last fread() call must have failed. */
713
int saved_errno = errno;
719
if (fclose (fp) == EOF)
722
#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
724
#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
726
struct mntent **mnttbl = getmnttbl (), **ent;
727
for (ent=mnttbl;*ent;ent++)
729
me = xmalloc (sizeof *me);
730
me->me_devname = xstrdup ( (*ent)->mt_resource);
731
me->me_mountdir = xstrdup ( (*ent)->mt_directory);
732
me->me_type = xstrdup ((*ent)->mt_fstype);
733
me->me_type_malloced = 1;
734
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
735
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
736
me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
738
/* Add to the linked list. */
740
mtail = &me->me_next;
746
#ifdef MOUNTED_GETMNTENT2 /* SVR4. */
749
char *table = MNTTAB;
754
# if defined F_RDLCK && defined F_SETLKW
755
/* MNTTAB_LOCK is a macro name of our own invention; it's not present in
756
e.g. Solaris 2.6. If the SVR4 folks ever define a macro
757
for this file name, we should use their macro name instead.
758
(Why not just lock MNTTAB directly? We don't know.) */
760
# define MNTTAB_LOCK "/etc/.mnttab.lock"
762
lockfd = open (MNTTAB_LOCK, O_RDONLY);
766
flock.l_type = F_RDLCK;
767
flock.l_whence = SEEK_SET;
770
while (fcntl (lockfd, F_SETLKW, &flock) == -1)
773
int saved_errno = errno;
779
else if (errno != ENOENT)
784
fp = fopen (table, "r");
789
while ((ret = getmntent (fp, &mnt)) == 0)
791
me = xmalloc (sizeof *me);
792
me->me_devname = xstrdup (mnt.mnt_special);
793
me->me_mountdir = xstrdup (mnt.mnt_mountp);
794
me->me_type = xstrdup (mnt.mnt_fstype);
795
me->me_type_malloced = 1;
796
me->me_dummy = MNT_IGNORE (&mnt) != 0;
797
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
798
me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
800
/* Add to the linked list. */
802
mtail = &me->me_next;
805
ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
808
if (0 <= lockfd && close (lockfd) != 0)
817
#endif /* MOUNTED_GETMNTENT2. */
819
#ifdef MOUNTED_VMOUNT /* AIX. */
822
char *entries, *thisent;
827
/* Ask how many bytes to allocate for the mounted file system info. */
828
if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
830
entries = xmalloc (bufsize);
832
/* Get the list of mounted file systems. */
833
n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
836
int saved_errno = errno;
842
for (i = 0, thisent = entries;
844
i++, thisent += vmp->vmt_length)
846
char *options, *ignore;
848
vmp = (struct vmount *) thisent;
849
me = xmalloc (sizeof *me);
850
if (vmp->vmt_flags & MNT_REMOTE)
855
/* Prepend the remote dirname. */
856
host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
857
dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
858
me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
859
strcpy (me->me_devname, host);
860
strcat (me->me_devname, ":");
861
strcat (me->me_devname, dir);
866
me->me_devname = xstrdup (thisent +
867
vmp->vmt_data[VMT_OBJECT].vmt_off);
869
me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
870
me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
871
me->me_type_malloced = 1;
872
options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
873
ignore = strstr (options, "ignore");
874
me->me_dummy = (ignore
875
&& (ignore == options || ignore[-1] == ',')
876
&& (ignore[sizeof "ignore" - 1] == ','
877
|| ignore[sizeof "ignore" - 1] == '\0'));
878
me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */
880
/* Add to the linked list. */
882
mtail = &me->me_next;
886
#endif /* MOUNTED_VMOUNT. */
894
int saved_errno = errno;
899
me = mount_list->me_next;
900
free (mount_list->me_devname);
901
free (mount_list->me_mountdir);
902
if (mount_list->me_type_malloced)
903
free (mount_list->me_type);