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