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