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