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