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