(read_filesystem_list): Add BeOS support.
[gnulib.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted filesystems
2    Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000 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 "mountlist.h"
25
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 #else
29 void free ();
30 #endif
31 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
32 # include <string.h>
33 #else
34 # include <strings.h>
35 #endif
36
37 #ifndef strstr
38 char *strstr ();
39 #endif
40 char *xmalloc ();
41 char *xrealloc ();
42 char *xstrdup ();
43 void error ();
44
45 #include <errno.h>
46 #ifndef errno
47 extern int errno;
48 #endif
49
50 #ifdef HAVE_FCNTL_H
51 # include <fcntl.h>
52 #endif
53
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57
58 #if HAVE_SYS_PARAM_H
59 # include <sys/param.h>
60 #endif
61
62 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
63 # include <sys/mount.h>
64 # include <sys/fs_types.h>
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(MNT_MNTTAB)       /* HP-UX.  */
71 #   define MOUNTED MNT_MNTTAB
72 #  endif
73 #  if defined(MNTTABNAME)       /* Dynix.  */
74 #   define MOUNTED MNTTABNAME
75 #  endif
76 # endif
77 #endif
78
79 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
80 # include <sys/mount.h>
81 #endif
82
83 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
84 # include <sys/mount.h>
85 # include <sys/fs_types.h>
86 #endif
87
88 #ifdef MOUNTED_NEXT_DEV         /* BeOS.  */
89 # include <fs_info.h>
90 # include <dirent.h>
91 #endif
92
93 #ifdef MOUNTED_FREAD            /* SVR2.  */
94 # include <mnttab.h>
95 #endif
96
97 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
98 # include <mnttab.h>
99 # include <sys/fstyp.h>
100 # include <sys/statfs.h>
101 #endif
102
103 #ifdef MOUNTED_LISTMNTENT
104 # include <mntent.h>
105 #endif
106
107 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
108 # include <sys/mnttab.h>
109 #endif
110
111 #ifdef MOUNTED_VMOUNT           /* AIX.  */
112 # include <fshelp.h>
113 # include <sys/vfs.h>
114 #endif
115
116 #ifdef DOLPHIN
117 /* So special that it's not worth putting this in autoconf.  */
118 # undef MOUNTED_FREAD_FSTYP
119 # define MOUNTED_GETMNTTBL
120 #endif
121
122 #if HAVE_SYS_MNTENT_H
123 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
124 # include <sys/mntent.h>
125 #endif
126
127 #if defined (MNTOPT_IGNORE) && defined (HAVE_HASMNTOPT)
128 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
129 #else
130 # define MNT_IGNORE(M) 0
131 #endif
132
133 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
134 /* Return the value of the hexadecimal number represented by CP.
135    No prefix (like '0x') or suffix (like 'h') is expected to be
136    part of CP. */
137 /* FIXME: this can overflow */
138
139 static int
140 xatoi (char *cp)
141 {
142   int val;
143
144   val = 0;
145   while (*cp)
146     {
147       if (*cp >= 'a' && *cp <= 'f')
148         val = val * 16 + *cp - 'a' + 10;
149       else if (*cp >= 'A' && *cp <= 'F')
150         val = val * 16 + *cp - 'A' + 10;
151       else if (*cp >= '0' && *cp <= '9')
152         val = val * 16 + *cp - '0';
153       else
154         break;
155       cp++;
156     }
157   return val;
158 }
159 #endif /* MOUNTED_GETMNTENT1.  */
160
161 #if MOUNTED_GETMNTINFO
162
163 # if ! HAVE_F_FSTYPENAME_IN_STATFS
164 static char *
165 fstype_to_string (short 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 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 filesystems, 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 nonzero, ensure that the filesystem type fields in
289    the returned list are valid.  Otherwise, they might not be.  */
290
291 struct mount_entry *
292 read_filesystem_list (int 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 = (struct mount_entry*) xmalloc(sizeof (struct mount_entry));
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_dummy = ME_DUMMY (me->me_devname, me->me_type);
318       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
319       me->me_dev = -1;
320       *mtail = me;
321       mtail = &me->me_next;
322     }
323     freemntlist(mntlist);
324   }
325 #endif
326
327 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
328   {
329     struct mntent *mnt;
330     char *table = MOUNTED;
331     FILE *fp;
332     char *devopt;
333
334     fp = setmntent (table, "r");
335     if (fp == NULL)
336       return NULL;
337
338     while ((mnt = getmntent (fp)))
339       {
340         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
341         me->me_devname = xstrdup (mnt->mnt_fsname);
342         me->me_mountdir = xstrdup (mnt->mnt_dir);
343         me->me_type = xstrdup (mnt->mnt_type);
344         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
345         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
346         devopt = strstr (mnt->mnt_opts, "dev=");
347         if (devopt)
348           {
349             if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
350               me->me_dev = xatoi (devopt + 6);
351             else
352               me->me_dev = xatoi (devopt + 4);
353           }
354         else
355           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
356
357         /* Add to the linked list. */
358         *mtail = me;
359         mtail = &me->me_next;
360       }
361
362     if (endmntent (fp) == 0)
363       goto free_then_fail;
364   }
365 #endif /* MOUNTED_GETMNTENT1. */
366
367 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
368   {
369     struct statfs *fsp;
370     int entries;
371
372     entries = getmntinfo (&fsp, MNT_NOWAIT);
373     if (entries < 0)
374       return NULL;
375     for (; entries-- > 0; fsp++)
376       {
377         char *fs_type = fsp_to_string (fsp);
378
379         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
380         me->me_devname = xstrdup (fsp->f_mntfromname);
381         me->me_mountdir = xstrdup (fsp->f_mntonname);
382         me->me_type = fs_type;
383         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
384         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
385         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
386
387         /* Add to the linked list. */
388         *mtail = me;
389         mtail = &me->me_next;
390       }
391   }
392 #endif /* MOUNTED_GETMNTINFO */
393
394 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
395   {
396     int offset = 0;
397     int val;
398     struct fs_data fsd;
399
400     while (errno = 0,
401            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
402                               (char *) 0)))
403       {
404         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
405         me->me_devname = xstrdup (fsd.fd_req.devname);
406         me->me_mountdir = xstrdup (fsd.fd_req.path);
407         me->me_type = gt_names[fsd.fd_req.fstype];
408         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
409         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
410         me->me_dev = fsd.fd_req.dev;
411
412         /* Add to the linked list. */
413         *mtail = me;
414         mtail = &me->me_next;
415       }
416     if (val < 0)
417       goto free_then_fail;
418   }
419 #endif /* MOUNTED_GETMNT. */
420
421 #if defined (MOUNTED_NEXT_DEV) /* BeOS */
422   {
423     /* The next_dev() and fs_stat_dev() system calls give the list of
424        all filesystems, including the information returned by statvfs()
425        (fs type, total blocks, free blocks etc.), but without the mount
426        point. But on BeOS all filesystems except / are mounted in the
427        rootfs, directly under /.
428        The directory name of the mount point is often, but not always,
429        identical to the volume name of the device.
430        We therefore get the list of subdirectories of /, and the list
431        of all filesystems, and match the two lists.  */
432
433     DIR *dirp;
434     struct rootdir_entry
435       {
436         char *name;
437         dev_t dev;
438         ino_t ino;
439         struct rootdir_entry *next;
440       };
441     struct rootdir_entry *rootdir_list;
442     struct rootdir_entry **rootdir_tail;
443     int32 pos;
444     dev_t dev;
445     fs_info fi;
446
447     /* All volumes are mounted in the rootfs, directly under /. */
448     rootdir_list = NULL;
449     rootdir_tail = &rootdir_list;
450     dirp = opendir ("/");
451     if (dirp)
452       {
453         struct dirent *d;
454
455         while ((d = readdir (dirp)) != NULL)
456           {
457             char *name;
458             struct stat statbuf;
459
460             if (strcmp (d->d_name, "..") == 0)
461               continue;
462
463             if (strcmp (d->d_name, ".") == 0)
464               name = xstrdup ("/");
465             else
466               {
467                 name = xmalloc (1 + strlen (d->d_name) + 1);
468                 name[0] = '/';
469                 strcpy (name + 1, d->d_name);
470               }
471
472             if (stat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
473               {
474                 struct rootdir_entry *re;
475
476                 re = (struct rootdir_entry *) xmalloc (sizeof (struct rootdir_entry));
477                 re->name = name;
478                 re->dev = statbuf.st_dev;
479                 re->ino = statbuf.st_ino;
480
481                 /* Add to the linked list.  */
482                 *rootdir_tail = re;
483                 rootdir_tail = &re->next;
484               }
485             else
486               free (name);
487           }
488         closedir (dirp);
489       }
490     *rootdir_tail = NULL;
491
492     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
493       if (fs_stat_dev (dev, &fi) >= 0)
494         {
495           /* Note: fi.dev == dev. */
496           struct rootdir_entry *re;
497
498           for (re = rootdir_list; re; re = re->next)
499             if (re->dev == fi.dev && re->ino == fi.root)
500               break;
501
502           me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
503           me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
504           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
505           me->me_type = xstrdup (fi.fsh_name);
506           me->me_dev = fi.dev;
507           me->me_dummy = 0;
508           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
509
510           /* Add to the linked list. */
511           *mtail = me;
512           mtail = &me->me_next;
513         }
514     *mtail = NULL;
515
516     while (rootdir_list != NULL)
517       {
518         struct rootdir_entry *re = rootdir_list;
519         rootdir_list = re->next;
520         free (re->name);
521         free (re);
522       }
523   }
524 #endif /* MOUNTED_NEXT_DEV */
525
526 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
527   {
528     int numsys, counter, bufsize;
529     struct statfs *stats;
530
531     numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT);
532     if (numsys < 0)
533       return (NULL);
534
535     bufsize = (1 + numsys) * sizeof (struct statfs);
536     stats = (struct statfs *)xmalloc (bufsize);
537     numsys = getfsstat (stats, bufsize, MNT_WAIT);
538
539     if (numsys < 0)
540       {
541         free (stats);
542         return (NULL);
543       }
544
545     for (counter = 0; counter < numsys; counter++)
546       {
547         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
548         me->me_devname = xstrdup (stats[counter].f_mntfromname);
549         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
550         me->me_type = mnt_names[stats[counter].f_type];
551         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
552         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
553         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
554
555         /* Add to the linked list. */
556         *mtail = me;
557         mtail = &me->me_next;
558       }
559
560     free (stats);
561   }
562 #endif /* MOUNTED_GETFSSTAT */
563
564 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23].  */
565   {
566     struct mnttab mnt;
567     char *table = "/etc/mnttab";
568     FILE *fp;
569
570     fp = fopen (table, "r");
571     if (fp == NULL)
572       return NULL;
573
574     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
575       {
576         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
577 # ifdef GETFSTYP                        /* SVR3.  */
578         me->me_devname = xstrdup (mnt.mt_dev);
579 # else
580         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
581         strcpy (me->me_devname, "/dev/");
582         strcpy (me->me_devname + 5, mnt.mt_dev);
583 # endif
584         me->me_mountdir = xstrdup (mnt.mt_filsys);
585         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
586         me->me_type = "";
587 # ifdef GETFSTYP                        /* SVR3.  */
588         if (need_fs_type)
589           {
590             struct statfs fsd;
591             char typebuf[FSTYPSZ];
592
593             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
594                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
595               me->me_type = xstrdup (typebuf);
596           }
597 # endif
598         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
599         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
600
601         /* Add to the linked list. */
602         *mtail = me;
603         mtail = &me->me_next;
604       }
605
606     if (ferror (fp))
607       {
608         int saved_errno = errno;
609         fclose (fp);
610         errno = saved_errno;
611         goto free_then_fail;
612       }
613
614     if (fclose (fp) == EOF)
615       goto free_then_fail;
616   }
617 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
618
619 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
620   {
621     struct mntent **mnttbl=getmnttbl(),**ent;
622     for (ent=mnttbl;*ent;ent++)
623       {
624         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
625         me->me_devname = xstrdup ( (*ent)->mt_resource);
626         me->me_mountdir = xstrdup( (*ent)->mt_directory);
627         me->me_type =  xstrdup ((*ent)->mt_fstype);
628         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
629         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
630         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
631
632         /* Add to the linked list. */
633         *mtail = me;
634         mtail = &me->me_next;
635       }
636     endmnttbl();
637   }
638 #endif
639
640 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
641   {
642     struct mnttab mnt;
643     char *table = MNTTAB;
644     FILE *fp;
645     int ret;
646     int lockfd = -1;
647
648 # if defined F_RDLCK && defined F_SETLKW
649     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
650        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
651        for this file name, we should use their macro name instead.
652        (Why not just lock MNTTAB directly?  We don't know.)  */
653 #  ifndef MNTTAB_LOCK
654 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
655 #  endif
656     lockfd = open (MNTTAB_LOCK, O_RDONLY);
657     if (0 <= lockfd)
658       {
659         struct flock flock;
660         flock.l_type = F_RDLCK;
661         flock.l_whence = SEEK_SET;
662         flock.l_start = 0;
663         flock.l_len = 0;
664         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
665           if (errno != EINTR)
666             {
667               int saved_errno = errno;
668               close (lockfd);
669               errno = saved_errno;
670               return NULL;
671             }
672       }
673     else if (errno != ENOENT)
674       return NULL;
675 # endif
676
677     errno = 0;
678     fp = fopen (table, "r");
679     if (fp == NULL)
680       ret = errno;
681     else
682       {
683         while ((ret = getmntent (fp, &mnt)) == 0)
684           {
685             me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
686             me->me_devname = xstrdup (mnt.mnt_special);
687             me->me_mountdir = xstrdup (mnt.mnt_mountp);
688             me->me_type = xstrdup (mnt.mnt_fstype);
689             me->me_dummy = MNT_IGNORE (&mnt) != 0;
690             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
691             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
692
693             /* Add to the linked list. */
694             *mtail = me;
695             mtail = &me->me_next;
696           }
697
698         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
699       }
700
701     if (0 <= lockfd && close (lockfd) != 0)
702       ret = errno;
703
704     if (0 <= ret)
705       {
706         errno = ret;
707         goto free_then_fail;
708       }
709   }
710 #endif /* MOUNTED_GETMNTENT2.  */
711
712 #ifdef MOUNTED_VMOUNT           /* AIX.  */
713   {
714     int bufsize;
715     char *entries, *thisent;
716     struct vmount *vmp;
717
718     /* Ask how many bytes to allocate for the mounted filesystem info.  */
719     mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
720     entries = xmalloc (bufsize);
721
722     /* Get the list of mounted filesystems.  */
723     mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
724
725     for (thisent = entries; thisent < entries + bufsize;
726          thisent += vmp->vmt_length)
727       {
728         vmp = (struct vmount *) thisent;
729         me = (struct mount_entry *) xmalloc (sizeof (struct mount_entry));
730         if (vmp->vmt_flags & MNT_REMOTE)
731           {
732             char *host, *path;
733
734             me->me_remote = 1;
735             /* Prepend the remote pathname.  */
736             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
737             path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
738             me->me_devname = xmalloc (strlen (host) + strlen (path) + 2);
739             strcpy (me->me_devname, host);
740             strcat (me->me_devname, ":");
741             strcat (me->me_devname, path);
742           }
743         else
744           {
745             me->me_remote = 0;
746             me->me_devname = xstrdup (thisent +
747                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
748           }
749         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
750         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
751         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
752         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
753
754         /* Add to the linked list. */
755         *mtail = me;
756         mtail = &me->me_next;
757       }
758     free (entries);
759   }
760 #endif /* MOUNTED_VMOUNT. */
761
762   *mtail = NULL;
763   return mount_list;
764
765
766  free_then_fail:
767   {
768     int saved_errno = errno;
769     *mtail = NULL;
770
771     while (mount_list)
772       {
773         me = mount_list->me_next;
774         free (mount_list->me_devname);
775         free (mount_list->me_mountdir);
776         /* FIXME: me_type is not always malloced.  */
777         free (mount_list);
778         mount_list = me;
779       }
780
781     errno = saved_errno;
782     return NULL;
783   }
784 }