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