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