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