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