avoid misc. warnings
[gnulib.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted file systems
2
3    Copyright (C) 1991, 1992, 1997-2008 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 #include "mountlist.h"
21
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "xalloc.h"
28
29 #include <errno.h>
30
31 #include <fcntl.h>
32
33 #include <unistd.h>
34
35 #if HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38
39 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
40 # if HAVE_SYS_UCRED_H
41 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
42                       NGROUPS is used as an array dimension in ucred.h */
43 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
44 # endif
45 # if HAVE_SYS_MOUNT_H
46 #  include <sys/mount.h>
47 # endif
48 # if HAVE_SYS_FS_TYPES_H
49 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
50 # endif
51 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
52 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
53 # else
54 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
55 # endif
56 #endif /* MOUNTED_GETFSSTAT */
57
58 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
59 # include <mntent.h>
60 # if !defined MOUNTED
61 #  if defined _PATH_MOUNTED     /* GNU libc  */
62 #   define MOUNTED _PATH_MOUNTED
63 #  endif
64 #  if defined MNT_MNTTAB        /* HP-UX.  */
65 #   define MOUNTED MNT_MNTTAB
66 #  endif
67 #  if defined MNTTABNAME        /* Dynix.  */
68 #   define MOUNTED MNTTABNAME
69 #  endif
70 # endif
71 #endif
72
73 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
74 # include <sys/mount.h>
75 #endif
76
77 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
78 # include <sys/statvfs.h>
79 #endif
80
81 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
82 # include <sys/mount.h>
83 # include <sys/fs_types.h>
84 #endif
85
86 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
87 # include <fs_info.h>
88 # include <dirent.h>
89 #endif
90
91 #ifdef MOUNTED_FREAD            /* SVR2.  */
92 # include <mnttab.h>
93 #endif
94
95 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
96 # include <mnttab.h>
97 # include <sys/fstyp.h>
98 # include <sys/statfs.h>
99 #endif
100
101 #ifdef MOUNTED_LISTMNTENT
102 # include <mntent.h>
103 #endif
104
105 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
106 # include <sys/mnttab.h>
107 #endif
108
109 #ifdef MOUNTED_VMOUNT           /* AIX.  */
110 # include <fshelp.h>
111 # include <sys/vfs.h>
112 #endif
113
114 #ifdef DOLPHIN
115 /* So special that it's not worth putting this in autoconf.  */
116 # undef MOUNTED_FREAD_FSTYP
117 # define MOUNTED_GETMNTTBL
118 #endif
119
120 #if HAVE_SYS_MNTENT_H
121 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
122 # include <sys/mntent.h>
123 #endif
124
125 #undef MNT_IGNORE
126 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
127 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
128 #else
129 # define MNT_IGNORE(M) 0
130 #endif
131
132 #if USE_UNLOCKED_IO
133 # include "unlocked-io.h"
134 #endif
135
136 #ifndef SIZE_MAX
137 # define SIZE_MAX ((size_t) -1)
138 #endif
139
140 /* The results of open() in this file are not used with fchdir,
141    therefore save some unnecessary work in fchdir.c.  */
142 #undef open
143 #undef close
144
145 /* The results of opendir() in this file are not used with dirfd and fchdir,
146    therefore save some unnecessary work in fchdir.c.  */
147 #undef opendir
148 #undef closedir
149
150 #ifndef ME_DUMMY
151 # define ME_DUMMY(Fs_name, Fs_type)             \
152     (strcmp (Fs_type, "autofs") == 0            \
153      || strcmp (Fs_type, "none") == 0           \
154      || strcmp (Fs_type, "proc") == 0           \
155      || strcmp (Fs_type, "subfs") == 0          \
156      /* for NetBSD 3.0 */                       \
157      || strcmp (Fs_type, "kernfs") == 0         \
158      /* for Irix 6.5 */                         \
159      || strcmp (Fs_type, "ignore") == 0)
160 #endif
161
162 #ifndef ME_REMOTE
163 /* A file system is `remote' if its Fs_name contains a `:'
164    or if (it is of type (smbfs or cifs) and its Fs_name starts with `//').  */
165 # define ME_REMOTE(Fs_name, Fs_type)            \
166     (strchr (Fs_name, ':') != NULL              \
167      || ((Fs_name)[0] == '/'                    \
168          && (Fs_name)[1] == '/'                 \
169          && (strcmp (Fs_type, "smbfs") == 0     \
170              || strcmp (Fs_type, "cifs") == 0)))
171 #endif
172
173 #if MOUNTED_GETMNTINFO
174
175 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
176 static char *
177 fstype_to_string (short int t)
178 {
179   switch (t)
180     {
181 #  ifdef MOUNT_PC
182     case MOUNT_PC:
183       return "pc";
184 #  endif
185 #  ifdef MOUNT_MFS
186     case MOUNT_MFS:
187       return "mfs";
188 #  endif
189 #  ifdef MOUNT_LO
190     case MOUNT_LO:
191       return "lo";
192 #  endif
193 #  ifdef MOUNT_TFS
194     case MOUNT_TFS:
195       return "tfs";
196 #  endif
197 #  ifdef MOUNT_TMP
198     case MOUNT_TMP:
199       return "tmp";
200 #  endif
201 #  ifdef MOUNT_UFS
202    case MOUNT_UFS:
203      return "ufs" ;
204 #  endif
205 #  ifdef MOUNT_NFS
206    case MOUNT_NFS:
207      return "nfs" ;
208 #  endif
209 #  ifdef MOUNT_MSDOS
210    case MOUNT_MSDOS:
211      return "msdos" ;
212 #  endif
213 #  ifdef MOUNT_LFS
214    case MOUNT_LFS:
215      return "lfs" ;
216 #  endif
217 #  ifdef MOUNT_LOFS
218    case MOUNT_LOFS:
219      return "lofs" ;
220 #  endif
221 #  ifdef MOUNT_FDESC
222    case MOUNT_FDESC:
223      return "fdesc" ;
224 #  endif
225 #  ifdef MOUNT_PORTAL
226    case MOUNT_PORTAL:
227      return "portal" ;
228 #  endif
229 #  ifdef MOUNT_NULL
230    case MOUNT_NULL:
231      return "null" ;
232 #  endif
233 #  ifdef MOUNT_UMAP
234    case MOUNT_UMAP:
235      return "umap" ;
236 #  endif
237 #  ifdef MOUNT_KERNFS
238    case MOUNT_KERNFS:
239      return "kernfs" ;
240 #  endif
241 #  ifdef MOUNT_PROCFS
242    case MOUNT_PROCFS:
243      return "procfs" ;
244 #  endif
245 #  ifdef MOUNT_AFS
246    case MOUNT_AFS:
247      return "afs" ;
248 #  endif
249 #  ifdef MOUNT_CD9660
250    case MOUNT_CD9660:
251      return "cd9660" ;
252 #  endif
253 #  ifdef MOUNT_UNION
254    case MOUNT_UNION:
255      return "union" ;
256 #  endif
257 #  ifdef MOUNT_DEVFS
258    case MOUNT_DEVFS:
259      return "devfs" ;
260 #  endif
261 #  ifdef MOUNT_EXT2FS
262    case MOUNT_EXT2FS:
263      return "ext2fs" ;
264 #  endif
265     default:
266       return "?";
267     }
268 }
269 # endif
270
271 static char *
272 fsp_to_string (const struct statfs *fsp)
273 {
274 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
275   return (char *) (fsp->f_fstypename);
276 # else
277   return fstype_to_string (fsp->f_type);
278 # endif
279 }
280
281 #endif /* MOUNTED_GETMNTINFO */
282
283 #ifdef MOUNTED_VMOUNT           /* AIX.  */
284 static char *
285 fstype_to_string (int t)
286 {
287   struct vfs_ent *e;
288
289   e = getvfsbytype (t);
290   if (!e || !e->vfsent_name)
291     return "none";
292   else
293     return e->vfsent_name;
294 }
295 #endif /* MOUNTED_VMOUNT */
296
297
298 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
299
300 #undef UNUSED_PARAM
301 #ifdef __linux__
302 # define UNUSED_PARAM _UNUSED_PARAMETER_
303 #else
304 # define UNUSED_PARAM
305 #endif
306
307 /* Return the device number from MOUNT_OPTIONS, if possible.
308    Otherwise return (dev_t) -1.  */
309 static dev_t
310 dev_from_mount_options (char const *mount_options UNUSED_PARAM)
311 {
312   /* GNU/Linux allows file system implementations to define their own
313      meaning for "dev=" mount options, so don't trust the meaning
314      here.  */
315 # ifndef __linux__
316
317   static char const dev_pattern[] = ",dev=";
318   char const *devopt = strstr (mount_options, dev_pattern);
319
320   if (devopt)
321     {
322       char const *optval = devopt + sizeof dev_pattern - 1;
323       char *optvalend;
324       unsigned long int dev;
325       errno = 0;
326       dev = strtoul (optval, &optvalend, 16);
327       if (optval != optvalend
328           && (*optvalend == '\0' || *optvalend == ',')
329           && ! (dev == ULONG_MAX && errno == ERANGE)
330           && dev == (dev_t) dev)
331         return dev;
332     }
333
334 # endif
335
336   return -1;
337 }
338
339 #endif
340
341 #undef UNUSED_PARAM
342 #ifdef GETFSTYP
343 # define UNUSED_PARAM
344 #else
345 # define UNUSED_PARAM _UNUSED_PARAMETER_
346 #endif
347
348 /* Return a list of the currently mounted file systems, or NULL on error.
349    Add each entry to the tail of the list so that they stay in order.
350    If NEED_FS_TYPE is true, ensure that the file system type fields in
351    the returned list are valid.  Otherwise, they might not be.  */
352
353 struct mount_entry *
354 read_file_system_list (bool need_fs_type UNUSED_PARAM)
355 {
356   struct mount_entry *mount_list;
357   struct mount_entry *me;
358   struct mount_entry **mtail = &mount_list;
359
360 #ifdef MOUNTED_LISTMNTENT
361   {
362     struct tabmntent *mntlist, *p;
363     struct mntent *mnt;
364     struct mount_entry *me;
365
366     /* the third and fourth arguments could be used to filter mounts,
367        but Crays doesn't seem to have any mounts that we want to
368        remove. Specifically, automount create normal NFS mounts.
369        */
370
371     if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
372       return NULL;
373     for (p = mntlist; p; p = p->next) {
374       mnt = p->ment;
375       me = xmalloc (sizeof *me);
376       me->me_devname = xstrdup (mnt->mnt_fsname);
377       me->me_mountdir = xstrdup (mnt->mnt_dir);
378       me->me_type = xstrdup (mnt->mnt_type);
379       me->me_type_malloced = 1;
380       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
381       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
382       me->me_dev = -1;
383       *mtail = me;
384       mtail = &me->me_next;
385     }
386     freemntlist (mntlist);
387   }
388 #endif
389
390 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
391   {
392     struct mntent *mnt;
393     char const *table = MOUNTED;
394     FILE *fp;
395
396     fp = setmntent (table, "r");
397     if (fp == NULL)
398       return NULL;
399
400     while ((mnt = getmntent (fp)))
401       {
402         me = xmalloc (sizeof *me);
403         me->me_devname = xstrdup (mnt->mnt_fsname);
404         me->me_mountdir = xstrdup (mnt->mnt_dir);
405         me->me_type = xstrdup (mnt->mnt_type);
406         me->me_type_malloced = 1;
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 = dev_from_mount_options (mnt->mnt_opts);
410
411         /* Add to the linked list. */
412         *mtail = me;
413         mtail = &me->me_next;
414       }
415
416     if (endmntent (fp) == 0)
417       goto free_then_fail;
418   }
419 #endif /* MOUNTED_GETMNTENT1. */
420
421 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
422   {
423     struct statfs *fsp;
424     int entries;
425
426     entries = getmntinfo (&fsp, MNT_NOWAIT);
427     if (entries < 0)
428       return NULL;
429     for (; entries-- > 0; fsp++)
430       {
431         char *fs_type = fsp_to_string (fsp);
432
433         me = xmalloc (sizeof *me);
434         me->me_devname = xstrdup (fsp->f_mntfromname);
435         me->me_mountdir = xstrdup (fsp->f_mntonname);
436         me->me_type = fs_type;
437         me->me_type_malloced = 0;
438         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
439         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
440         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
441
442         /* Add to the linked list. */
443         *mtail = me;
444         mtail = &me->me_next;
445       }
446   }
447 #endif /* MOUNTED_GETMNTINFO */
448
449 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
450   {
451     struct statvfs *fsp;
452     int entries;
453
454     entries = getmntinfo (&fsp, MNT_NOWAIT);
455     if (entries < 0)
456       return NULL;
457     for (; entries-- > 0; fsp++)
458       {
459         me = xmalloc (sizeof *me);
460         me->me_devname = xstrdup (fsp->f_mntfromname);
461         me->me_mountdir = xstrdup (fsp->f_mntonname);
462         me->me_type = xstrdup (fsp->f_fstypename);
463         me->me_type_malloced = 1;
464         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
465         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
466         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
467
468         /* Add to the linked list. */
469         *mtail = me;
470         mtail = &me->me_next;
471       }
472   }
473 #endif /* MOUNTED_GETMNTINFO2 */
474
475 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
476   {
477     int offset = 0;
478     int val;
479     struct fs_data fsd;
480
481     while (errno = 0,
482            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
483                               (char *) 0)))
484       {
485         me = xmalloc (sizeof *me);
486         me->me_devname = xstrdup (fsd.fd_req.devname);
487         me->me_mountdir = xstrdup (fsd.fd_req.path);
488         me->me_type = gt_names[fsd.fd_req.fstype];
489         me->me_type_malloced = 0;
490         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
491         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
492         me->me_dev = fsd.fd_req.dev;
493
494         /* Add to the linked list. */
495         *mtail = me;
496         mtail = &me->me_next;
497       }
498     if (val < 0)
499       goto free_then_fail;
500   }
501 #endif /* MOUNTED_GETMNT. */
502
503 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
504   {
505     /* The next_dev() and fs_stat_dev() system calls give the list of
506        all file systems, including the information returned by statvfs()
507        (fs type, total blocks, free blocks etc.), but without the mount
508        point. But on BeOS all file systems except / are mounted in the
509        rootfs, directly under /.
510        The directory name of the mount point is often, but not always,
511        identical to the volume name of the device.
512        We therefore get the list of subdirectories of /, and the list
513        of all file systems, and match the two lists.  */
514
515     DIR *dirp;
516     struct rootdir_entry
517       {
518         char *name;
519         dev_t dev;
520         ino_t ino;
521         struct rootdir_entry *next;
522       };
523     struct rootdir_entry *rootdir_list;
524     struct rootdir_entry **rootdir_tail;
525     int32 pos;
526     dev_t dev;
527     fs_info fi;
528
529     /* All volumes are mounted in the rootfs, directly under /. */
530     rootdir_list = NULL;
531     rootdir_tail = &rootdir_list;
532     dirp = opendir ("/");
533     if (dirp)
534       {
535         struct dirent *d;
536
537         while ((d = readdir (dirp)) != NULL)
538           {
539             char *name;
540             struct stat statbuf;
541
542             if (strcmp (d->d_name, "..") == 0)
543               continue;
544
545             if (strcmp (d->d_name, ".") == 0)
546               name = xstrdup ("/");
547             else
548               {
549                 name = xmalloc (1 + strlen (d->d_name) + 1);
550                 name[0] = '/';
551                 strcpy (name + 1, d->d_name);
552               }
553
554             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
555               {
556                 struct rootdir_entry *re = xmalloc (sizeof *re);
557                 re->name = name;
558                 re->dev = statbuf.st_dev;
559                 re->ino = statbuf.st_ino;
560
561                 /* Add to the linked list.  */
562                 *rootdir_tail = re;
563                 rootdir_tail = &re->next;
564               }
565             else
566               free (name);
567           }
568         closedir (dirp);
569       }
570     *rootdir_tail = NULL;
571
572     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
573       if (fs_stat_dev (dev, &fi) >= 0)
574         {
575           /* Note: fi.dev == dev. */
576           struct rootdir_entry *re;
577
578           for (re = rootdir_list; re; re = re->next)
579             if (re->dev == fi.dev && re->ino == fi.root)
580               break;
581
582           me = xmalloc (sizeof *me);
583           me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
584           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
585           me->me_type = xstrdup (fi.fsh_name);
586           me->me_type_malloced = 1;
587           me->me_dev = fi.dev;
588           me->me_dummy = 0;
589           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
590
591           /* Add to the linked list. */
592           *mtail = me;
593           mtail = &me->me_next;
594         }
595     *mtail = NULL;
596
597     while (rootdir_list != NULL)
598       {
599         struct rootdir_entry *re = rootdir_list;
600         rootdir_list = re->next;
601         free (re->name);
602         free (re);
603       }
604   }
605 #endif /* MOUNTED_FS_STAT_DEV */
606
607 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
608   {
609     int numsys, counter;
610     size_t bufsize;
611     struct statfs *stats;
612
613     numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
614     if (numsys < 0)
615       return (NULL);
616     if (SIZE_MAX / sizeof *stats <= numsys)
617       xalloc_die ();
618
619     bufsize = (1 + numsys) * sizeof *stats;
620     stats = xmalloc (bufsize);
621     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
622
623     if (numsys < 0)
624       {
625         free (stats);
626         return (NULL);
627       }
628
629     for (counter = 0; counter < numsys; counter++)
630       {
631         me = xmalloc (sizeof *me);
632         me->me_devname = xstrdup (stats[counter].f_mntfromname);
633         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
634         me->me_type = xstrdup (FS_TYPE (stats[counter]));
635         me->me_type_malloced = 1;
636         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
637         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
638         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
639
640         /* Add to the linked list. */
641         *mtail = me;
642         mtail = &me->me_next;
643       }
644
645     free (stats);
646   }
647 #endif /* MOUNTED_GETFSSTAT */
648
649 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
650   {
651     struct mnttab mnt;
652     char *table = "/etc/mnttab";
653     FILE *fp;
654
655     fp = fopen (table, "r");
656     if (fp == NULL)
657       return NULL;
658
659     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
660       {
661         me = xmalloc (sizeof *me);
662 # ifdef GETFSTYP                        /* SVR3.  */
663         me->me_devname = xstrdup (mnt.mt_dev);
664 # else
665         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
666         strcpy (me->me_devname, "/dev/");
667         strcpy (me->me_devname + 5, mnt.mt_dev);
668 # endif
669         me->me_mountdir = xstrdup (mnt.mt_filsys);
670         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
671         me->me_type = "";
672         me->me_type_malloced = 0;
673 # ifdef GETFSTYP                        /* SVR3.  */
674         if (need_fs_type)
675           {
676             struct statfs fsd;
677             char typebuf[FSTYPSZ];
678
679             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
680                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
681               {
682                 me->me_type = xstrdup (typebuf);
683                 me->me_type_malloced = 1;
684               }
685           }
686 # endif
687         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
688         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
689
690         /* Add to the linked list. */
691         *mtail = me;
692         mtail = &me->me_next;
693       }
694
695     if (ferror (fp))
696       {
697         /* The last fread() call must have failed.  */
698         int saved_errno = errno;
699         fclose (fp);
700         errno = saved_errno;
701         goto free_then_fail;
702       }
703
704     if (fclose (fp) == EOF)
705       goto free_then_fail;
706   }
707 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
708
709 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes its own way.  */
710   {
711     struct mntent **mnttbl = getmnttbl (), **ent;
712     for (ent=mnttbl;*ent;ent++)
713       {
714         me = xmalloc (sizeof *me);
715         me->me_devname = xstrdup ( (*ent)->mt_resource);
716         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
717         me->me_type = xstrdup ((*ent)->mt_fstype);
718         me->me_type_malloced = 1;
719         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
720         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
721         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
722
723         /* Add to the linked list. */
724         *mtail = me;
725         mtail = &me->me_next;
726       }
727     endmnttbl ();
728   }
729 #endif
730
731 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
732   {
733     struct mnttab mnt;
734     char *table = MNTTAB;
735     FILE *fp;
736     int ret;
737     int lockfd = -1;
738
739 # if defined F_RDLCK && defined F_SETLKW
740     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
741        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
742        for this file name, we should use their macro name instead.
743        (Why not just lock MNTTAB directly?  We don't know.)  */
744 #  ifndef MNTTAB_LOCK
745 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
746 #  endif
747     lockfd = open (MNTTAB_LOCK, O_RDONLY);
748     if (0 <= lockfd)
749       {
750         struct flock flock;
751         flock.l_type = F_RDLCK;
752         flock.l_whence = SEEK_SET;
753         flock.l_start = 0;
754         flock.l_len = 0;
755         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
756           if (errno != EINTR)
757             {
758               int saved_errno = errno;
759               close (lockfd);
760               errno = saved_errno;
761               return NULL;
762             }
763       }
764     else if (errno != ENOENT)
765       return NULL;
766 # endif
767
768     errno = 0;
769     fp = fopen (table, "r");
770     if (fp == NULL)
771       ret = errno;
772     else
773       {
774         while ((ret = getmntent (fp, &mnt)) == 0)
775           {
776             me = xmalloc (sizeof *me);
777             me->me_devname = xstrdup (mnt.mnt_special);
778             me->me_mountdir = xstrdup (mnt.mnt_mountp);
779             me->me_type = xstrdup (mnt.mnt_fstype);
780             me->me_type_malloced = 1;
781             me->me_dummy = MNT_IGNORE (&mnt) != 0;
782             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
783             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
784
785             /* Add to the linked list. */
786             *mtail = me;
787             mtail = &me->me_next;
788           }
789
790         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
791       }
792
793     if (0 <= lockfd && close (lockfd) != 0)
794       ret = errno;
795
796     if (0 <= ret)
797       {
798         errno = ret;
799         goto free_then_fail;
800       }
801   }
802 #endif /* MOUNTED_GETMNTENT2.  */
803
804 #ifdef MOUNTED_VMOUNT           /* AIX.  */
805   {
806     int bufsize;
807     char *entries, *thisent;
808     struct vmount *vmp;
809     int n_entries;
810     int i;
811
812     /* Ask how many bytes to allocate for the mounted file system info.  */
813     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
814       return NULL;
815     entries = xmalloc (bufsize);
816
817     /* Get the list of mounted file systems.  */
818     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
819     if (n_entries < 0)
820       {
821         int saved_errno = errno;
822         free (entries);
823         errno = saved_errno;
824         return NULL;
825       }
826
827     for (i = 0, thisent = entries;
828          i < n_entries;
829          i++, thisent += vmp->vmt_length)
830       {
831         char *options, *ignore;
832
833         vmp = (struct vmount *) thisent;
834         me = xmalloc (sizeof *me);
835         if (vmp->vmt_flags & MNT_REMOTE)
836           {
837             char *host, *dir;
838
839             me->me_remote = 1;
840             /* Prepend the remote dirname.  */
841             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
842             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
843             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
844             strcpy (me->me_devname, host);
845             strcat (me->me_devname, ":");
846             strcat (me->me_devname, dir);
847           }
848         else
849           {
850             me->me_remote = 0;
851             me->me_devname = xstrdup (thisent +
852                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
853           }
854         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
855         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
856         me->me_type_malloced = 1;
857         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
858         ignore = strstr (options, "ignore");
859         me->me_dummy = (ignore
860                         && (ignore == options || ignore[-1] == ',')
861                         && (ignore[sizeof "ignore" - 1] == ','
862                             || ignore[sizeof "ignore" - 1] == '\0'));
863         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
864
865         /* Add to the linked list. */
866         *mtail = me;
867         mtail = &me->me_next;
868       }
869     free (entries);
870   }
871 #endif /* MOUNTED_VMOUNT. */
872
873   *mtail = NULL;
874   return mount_list;
875
876
877  free_then_fail:
878   {
879     int saved_errno = errno;
880     *mtail = NULL;
881
882     while (mount_list)
883       {
884         me = mount_list->me_next;
885         free (mount_list->me_devname);
886         free (mount_list->me_mountdir);
887         if (mount_list->me_type_malloced)
888           free (mount_list->me_type);
889         free (mount_list);
890         mount_list = me;
891       }
892
893     errno = saved_errno;
894     return NULL;
895   }
896 }