Comment about the validity of errno.
[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         /* The last fread() call must have failed.  */
616         int saved_errno = errno;
617         fclose (fp);
618         errno = saved_errno;
619         goto free_then_fail;
620       }
621
622     if (fclose (fp) == EOF)
623       goto free_then_fail;
624   }
625 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
626
627 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
628   {
629     struct mntent **mnttbl = getmnttbl (), **ent;
630     for (ent=mnttbl;*ent;ent++)
631       {
632         me = xmalloc (sizeof (struct mount_entry));
633         me->me_devname = xstrdup ( (*ent)->mt_resource);
634         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
635         me->me_type =  xstrdup ((*ent)->mt_fstype);
636         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
637         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
638         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
639
640         /* Add to the linked list. */
641         *mtail = me;
642         mtail = &me->me_next;
643       }
644     endmnttbl ();
645   }
646 #endif
647
648 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
649   {
650     struct mnttab mnt;
651     char *table = MNTTAB;
652     FILE *fp;
653     int ret;
654     int lockfd = -1;
655
656 # if defined F_RDLCK && defined F_SETLKW
657     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
658        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
659        for this file name, we should use their macro name instead.
660        (Why not just lock MNTTAB directly?  We don't know.)  */
661 #  ifndef MNTTAB_LOCK
662 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
663 #  endif
664     lockfd = open (MNTTAB_LOCK, O_RDONLY);
665     if (0 <= lockfd)
666       {
667         struct flock flock;
668         flock.l_type = F_RDLCK;
669         flock.l_whence = SEEK_SET;
670         flock.l_start = 0;
671         flock.l_len = 0;
672         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
673           if (errno != EINTR)
674             {
675               int saved_errno = errno;
676               close (lockfd);
677               errno = saved_errno;
678               return NULL;
679             }
680       }
681     else if (errno != ENOENT)
682       return NULL;
683 # endif
684
685     errno = 0;
686     fp = fopen (table, "r");
687     if (fp == NULL)
688       ret = errno;
689     else
690       {
691         while ((ret = getmntent (fp, &mnt)) == 0)
692           {
693             me = xmalloc (sizeof (struct mount_entry));
694             me->me_devname = xstrdup (mnt.mnt_special);
695             me->me_mountdir = xstrdup (mnt.mnt_mountp);
696             me->me_type = xstrdup (mnt.mnt_fstype);
697             me->me_dummy = MNT_IGNORE (&mnt) != 0;
698             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
699             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
700
701             /* Add to the linked list. */
702             *mtail = me;
703             mtail = &me->me_next;
704           }
705
706         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
707       }
708
709     if (0 <= lockfd && close (lockfd) != 0)
710       ret = errno;
711
712     if (0 <= ret)
713       {
714         errno = ret;
715         goto free_then_fail;
716       }
717   }
718 #endif /* MOUNTED_GETMNTENT2.  */
719
720 #ifdef MOUNTED_VMOUNT           /* AIX.  */
721   {
722     int bufsize;
723     char *entries, *thisent;
724     struct vmount *vmp;
725     int n_entries;
726     int i;
727
728     /* Ask how many bytes to allocate for the mounted filesystem info.  */
729     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
730       return NULL;
731     entries = xmalloc (bufsize);
732
733     /* Get the list of mounted filesystems.  */
734     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
735     if (n_entries < 0)
736       {
737         int saved_errno = errno;
738         free (entries);
739         errno = saved_errno;
740         return NULL;
741       }
742
743     for (i = 0, thisent = entries;
744          i < n_entries;
745          i++, thisent += vmp->vmt_length)
746       {
747         char *options, *ignore;
748
749         vmp = (struct vmount *) thisent;
750         me = xmalloc (sizeof (struct mount_entry));
751         if (vmp->vmt_flags & MNT_REMOTE)
752           {
753             char *host, *path;
754
755             me->me_remote = 1;
756             /* Prepend the remote pathname.  */
757             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
758             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
759             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
760             strcpy (me->me_devname, host);
761             strcat (me->me_devname, ":");
762             strcat (me->me_devname, path);
763           }
764         else
765           {
766             me->me_remote = 0;
767             me->me_devname = xstrdup (thisent +
768                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
769           }
770         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
771         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
772         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
773         ignore = strstr (options, "ignore");
774         me->me_dummy = (ignore
775                         && (ignore == options || ignore[-1] == ',')
776                         && (ignore[sizeof "ignore" - 1] == ','
777                             || ignore[sizeof "ignore" - 1] == '\0'));
778         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
779
780         /* Add to the linked list. */
781         *mtail = me;
782         mtail = &me->me_next;
783       }
784     free (entries);
785   }
786 #endif /* MOUNTED_VMOUNT. */
787
788   *mtail = NULL;
789   return mount_list;
790
791
792  free_then_fail:
793   {
794     int saved_errno = errno;
795     *mtail = NULL;
796
797     while (mount_list)
798       {
799         me = mount_list->me_next;
800         free (mount_list->me_devname);
801         free (mount_list->me_mountdir);
802         /* FIXME: me_type is not always malloced.  */
803         free (mount_list);
804         mount_list = me;
805       }
806
807     errno = saved_errno;
808     return NULL;
809   }
810 }