Code

Fix tests for exact matches when searching filesystems
[nagiosplug.git] / lib / mountlist.c
1 /* mountlist.c -- return a list of mounted file systems
3    Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
4    2004, 2005 Free Software Foundation, Inc.
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include "mountlist.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include "xalloc.h"
32 #ifndef strstr
33 char *strstr ();
34 #endif
36 #include <errno.h>
38 #include <fcntl.h>
40 #include <unistd.h>
42 #if HAVE_SYS_PARAM_H
43 # include <sys/param.h>
44 #endif
46 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
47 # if HAVE_SYS_UCRED_H
48 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
49                       NGROUPS is used as an array dimension in ucred.h */
50 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
51 # endif
52 # if HAVE_SYS_MOUNT_H
53 #  include <sys/mount.h>
54 # endif
55 # if HAVE_SYS_FS_TYPES_H
56 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
57 # endif
58 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
59 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
60 # else
61 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
62 # endif
63 #endif /* MOUNTED_GETFSSTAT */
65 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
66 # include <mntent.h>
67 # if !defined MOUNTED
68 #  if defined _PATH_MOUNTED     /* GNU libc  */
69 #   define MOUNTED _PATH_MOUNTED
70 #  endif
71 #  if defined MNT_MNTTAB        /* HP-UX.  */
72 #   define MOUNTED MNT_MNTTAB
73 #  endif
74 #  if defined MNTTABNAME        /* Dynix.  */
75 #   define MOUNTED MNTTABNAME
76 #  endif
77 # endif
78 #endif
80 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
81 # include <sys/mount.h>
82 #endif
84 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
85 # include <sys/mount.h>
86 # include <sys/fs_types.h>
87 #endif
89 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
90 # include <fs_info.h>
91 # include <dirent.h>
92 #endif
94 #ifdef MOUNTED_FREAD            /* SVR2.  */
95 # include <mnttab.h>
96 #endif
98 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
99 # include <mnttab.h>
100 # include <sys/fstyp.h>
101 # include <sys/statfs.h>
102 #endif
104 #ifdef MOUNTED_LISTMNTENT
105 # include <mntent.h>
106 #endif
108 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
109 # include <sys/mnttab.h>
110 #endif
112 #ifdef MOUNTED_VMOUNT           /* AIX.  */
113 # include <fshelp.h>
114 # include <sys/vfs.h>
115 #endif
117 #ifdef DOLPHIN
118 /* So special that it's not worth putting this in autoconf.  */
119 # undef MOUNTED_FREAD_FSTYP
120 # define MOUNTED_GETMNTTBL
121 #endif
123 #if HAVE_SYS_MNTENT_H
124 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
125 # include <sys/mntent.h>
126 #endif
128 #undef MNT_IGNORE
129 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
130 # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE)
131 #else
132 # define MNT_IGNORE(M) 0
133 #endif
135 #if USE_UNLOCKED_IO
136 # include "unlocked-io.h"
137 #endif
139 #ifndef SIZE_MAX
140 # define SIZE_MAX ((size_t) -1)
141 #endif
143 #ifndef ME_DUMMY
144 # define ME_DUMMY(Fs_name, Fs_type)             \
145     (strcmp (Fs_type, "autofs") == 0            \
146      || strcmp (Fs_type, "none") == 0           \
147      || strcmp (Fs_type, "proc") == 0           \
148      || strcmp (Fs_type, "subfs") == 0          \
149      /* for Irix 6.5 */                         \
150      || strcmp (Fs_type, "ignore") == 0)
151 #endif
153 #ifndef ME_REMOTE
154 /* A file system is `remote' if its Fs_name contains a `:'
155    or if (it is of type smbfs and its Fs_name starts with `//').  */
156 # define ME_REMOTE(Fs_name, Fs_type)            \
157     (strchr (Fs_name, ':') != 0                 \
158      || ((Fs_name)[0] == '/'                    \
159          && (Fs_name)[1] == '/'                 \
160          && strcmp (Fs_type, "smbfs") == 0))
161 #endif
163 #if MOUNTED_GETMNTINFO
165 # if ! HAVE_F_FSTYPENAME_IN_STATFS
166 static char *
167 fstype_to_string (short int t)
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     }
259 # endif /* ! HAVE_F_FSTYPENAME_IN_STATFS */
261 /* __NetBSD__ || BSD_NET2 || __OpenBSD__ */
262 static char *
263 fsp_to_string (const struct statfs *fsp)
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
272 #endif /* MOUNTED_GETMNTINFO */
274 #ifdef MOUNTED_VMOUNT           /* AIX.  */
275 static char *
276 fstype_to_string (int t)
278   struct vfs_ent *e;
280   e = getvfsbytype (t);
281   if (!e || !e->vfsent_name)
282     return "none";
283   else
284     return e->vfsent_name;
286 #endif /* MOUNTED_VMOUNT */
288 /* Return a list of the currently mounted file systems, 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 true, ensure that the file system type fields in
291    the returned list are valid.  Otherwise, they might not be.  */
293 struct mount_entry *
294 read_file_system_list (bool need_fs_type)
296   struct mount_entry *mount_list;
297   struct mount_entry *me;
298   struct mount_entry **mtail = &mount_list;
300 #ifdef MOUNTED_LISTMNTENT
301   {
302     struct tabmntent *mntlist, *p;
303     struct mntent *mnt;
304     struct mount_entry *me;
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        */
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 = xmalloc (sizeof *me);
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_type_malloced = 1;
320       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
321       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
322       me->me_dev = -1;
323       *mtail = me;
324       mtail = &me->me_next;
325     }
326     freemntlist (mntlist);
327   }
328 #endif
330 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
331   {
332     struct mntent *mnt;
333     char *table = MOUNTED;
334     FILE *fp;
335     char *devopt;
337     fp = setmntent (table, "r");
338     if (fp == NULL)
339       return NULL;
341     while ((mnt = getmntent (fp)))
342       {
343         me = xmalloc (sizeof *me);
344         me->me_devname = xstrdup (mnt->mnt_fsname);
345         me->me_mountdir = xstrdup (mnt->mnt_dir);
346         me->me_type = xstrdup (mnt->mnt_type);
347         me->me_type_malloced = 1;
348         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
349         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
350         devopt = strstr (mnt->mnt_opts, "dev=");
351         if (devopt)
352           me->me_dev = strtoul (devopt + 4, NULL, 16);
353         else
354           me->me_dev = (dev_t) -1;      /* Magic; means not known yet. */
356         /* Add to the linked list. */
357         *mtail = me;
358         mtail = &me->me_next;
359       }
361     if (endmntent (fp) == 0)
362       goto free_then_fail;
363   }
364 #endif /* MOUNTED_GETMNTENT1. */
366 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
367   {
368     struct statfs *fsp;
369     int entries;
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);
378         me = xmalloc (sizeof *me);
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_type_malloced = 0;
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. */
387         /* Add to the linked list. */
388         *mtail = me;
389         mtail = &me->me_next;
390       }
391   }
392 #endif /* MOUNTED_GETMNTINFO */
394 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
395   {
396     int offset = 0;
397     int val;
398     struct fs_data fsd;
400     while (errno = 0,
401            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
402                               (char *) 0)))
403       {
404         me = xmalloc (sizeof *me);
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_type_malloced = 0;
409         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
410         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
411         me->me_dev = fsd.fd_req.dev;
413         /* Add to the linked list. */
414         *mtail = me;
415         mtail = &me->me_next;
416       }
417     if (val < 0)
418       goto free_then_fail;
419   }
420 #endif /* MOUNTED_GETMNT. */
422 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
423   {
424     /* The next_dev() and fs_stat_dev() system calls give the list of
425        all file systems, including the information returned by statvfs()
426        (fs type, total blocks, free blocks etc.), but without the mount
427        point. But on BeOS all file systems except / are mounted in the
428        rootfs, directly under /.
429        The directory name of the mount point is often, but not always,
430        identical to the volume name of the device.
431        We therefore get the list of subdirectories of /, and the list
432        of all file systems, and match the two lists.  */
434     DIR *dirp;
435     struct rootdir_entry
436       {
437         char *name;
438         dev_t dev;
439         ino_t ino;
440         struct rootdir_entry *next;
441       };
442     struct rootdir_entry *rootdir_list;
443     struct rootdir_entry **rootdir_tail;
444     int32 pos;
445     dev_t dev;
446     fs_info fi;
448     /* All volumes are mounted in the rootfs, directly under /. */
449     rootdir_list = NULL;
450     rootdir_tail = &rootdir_list;
451     dirp = opendir ("/");
452     if (dirp)
453       {
454         struct dirent *d;
456         while ((d = readdir (dirp)) != NULL)
457           {
458             char *name;
459             struct stat statbuf;
461             if (strcmp (d->d_name, "..") == 0)
462               continue;
464             if (strcmp (d->d_name, ".") == 0)
465               name = xstrdup ("/");
466             else
467               {
468                 name = xmalloc (1 + strlen (d->d_name) + 1);
469                 name[0] = '/';
470                 strcpy (name + 1, d->d_name);
471               }
473             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
474               {
475                 struct rootdir_entry *re = xmalloc (sizeof *re);
476                 re->name = name;
477                 re->dev = statbuf.st_dev;
478                 re->ino = statbuf.st_ino;
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;
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;
497           for (re = rootdir_list; re; re = re->next)
498             if (re->dev == fi.dev && re->ino == fi.root)
499               break;
501           me = xmalloc (sizeof *me);
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_type_malloced = 1;
506           me->me_dev = fi.dev;
507           me->me_dummy = 0;
508           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
510           /* Add to the linked list. */
511           *mtail = me;
512           mtail = &me->me_next;
513         }
514     *mtail = NULL;
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_FS_STAT_DEV */
526 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
527   {
528     int numsys, counter;
529     size_t bufsize;
530     struct statfs *stats;
532     numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
533     if (numsys < 0)
534       return (NULL);
535     if (SIZE_MAX / sizeof *stats <= numsys)
536       xalloc_die ();
538     bufsize = (1 + numsys) * sizeof *stats;
539     stats = xmalloc (bufsize);
540     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
542     if (numsys < 0)
543       {
544         free (stats);
545         return (NULL);
546       }
548     for (counter = 0; counter < numsys; counter++)
549       {
550         me = xmalloc (sizeof *me);
551         me->me_devname = xstrdup (stats[counter].f_mntfromname);
552         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
553         me->me_type = xstrdup (FS_TYPE (stats[counter]));
554         me->me_type_malloced = 1;
555         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
556         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
557         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
559         /* Add to the linked list. */
560         *mtail = me;
561         mtail = &me->me_next;
562       }
564     free (stats);
565   }
566 #endif /* MOUNTED_GETFSSTAT */
568 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
569   {
570     struct mnttab mnt;
571     char *table = "/etc/mnttab";
572     FILE *fp;
574     fp = fopen (table, "r");
575     if (fp == NULL)
576       return NULL;
578     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
579       {
580         me = xmalloc (sizeof *me);
581 # ifdef GETFSTYP                        /* SVR3.  */
582         me->me_devname = xstrdup (mnt.mt_dev);
583 # else
584         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
585         strcpy (me->me_devname, "/dev/");
586         strcpy (me->me_devname + 5, mnt.mt_dev);
587 # endif
588         me->me_mountdir = xstrdup (mnt.mt_filsys);
589         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
590         me->me_type = "";
591         me->me_type_malloced = 0;
592 # ifdef GETFSTYP                        /* SVR3.  */
593         if (need_fs_type)
594           {
595             struct statfs fsd;
596             char typebuf[FSTYPSZ];
598             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
599                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
600               {
601                 me->me_type = xstrdup (typebuf);
602                 me->me_type_malloced = 1;
603               }
604           }
605 # endif
606         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
607         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
609         /* Add to the linked list. */
610         *mtail = me;
611         mtail = &me->me_next;
612       }
614     if (ferror (fp))
615       {
616         /* The last fread() call must have failed.  */
617         int saved_errno = errno;
618         fclose (fp);
619         errno = saved_errno;
620         goto free_then_fail;
621       }
623     if (fclose (fp) == EOF)
624       goto free_then_fail;
625   }
626 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
628 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes it's own way */
629   {
630     struct mntent **mnttbl = getmnttbl (), **ent;
631     for (ent=mnttbl;*ent;ent++)
632       {
633         me = xmalloc (sizeof *me);
634         me->me_devname = xstrdup ( (*ent)->mt_resource);
635         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
636         me->me_type = xstrdup ((*ent)->mt_fstype);
637         me->me_type_malloced = 1;
638         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
639         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
640         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
642         /* Add to the linked list. */
643         *mtail = me;
644         mtail = &me->me_next;
645       }
646     endmnttbl ();
647   }
648 #endif
650 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
651   {
652     struct mnttab mnt;
653     char *table = MNTTAB;
654     FILE *fp;
655     int ret;
656     int lockfd = -1;
658 # if defined F_RDLCK && defined F_SETLKW
659     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
660        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
661        for this file name, we should use their macro name instead.
662        (Why not just lock MNTTAB directly?  We don't know.)  */
663 #  ifndef MNTTAB_LOCK
664 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
665 #  endif
666     lockfd = open (MNTTAB_LOCK, O_RDONLY);
667     if (0 <= lockfd)
668       {
669         struct flock flock;
670         flock.l_type = F_RDLCK;
671         flock.l_whence = SEEK_SET;
672         flock.l_start = 0;
673         flock.l_len = 0;
674         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
675           if (errno != EINTR)
676             {
677               int saved_errno = errno;
678               close (lockfd);
679               errno = saved_errno;
680               return NULL;
681             }
682       }
683     else if (errno != ENOENT)
684       return NULL;
685 # endif
687     errno = 0;
688     fp = fopen (table, "r");
689     if (fp == NULL)
690       ret = errno;
691     else
692       {
693         while ((ret = getmntent (fp, &mnt)) == 0)
694           {
695             me = xmalloc (sizeof *me);
696             me->me_devname = xstrdup (mnt.mnt_special);
697             me->me_mountdir = xstrdup (mnt.mnt_mountp);
698             me->me_type = xstrdup (mnt.mnt_fstype);
699             me->me_type_malloced = 1;
700             me->me_dummy = MNT_IGNORE (&mnt) != 0;
701             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
702             me->me_dev = (dev_t) -1;    /* Magic; means not known yet. */
704             /* Add to the linked list. */
705             *mtail = me;
706             mtail = &me->me_next;
707           }
709         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
710       }
712     if (0 <= lockfd && close (lockfd) != 0)
713       ret = errno;
715     if (0 <= ret)
716       {
717         errno = ret;
718         goto free_then_fail;
719       }
720   }
721 #endif /* MOUNTED_GETMNTENT2.  */
723 #ifdef MOUNTED_VMOUNT           /* AIX.  */
724   {
725     int bufsize;
726     char *entries, *thisent;
727     struct vmount *vmp;
728     int n_entries;
729     int i;
731     /* Ask how many bytes to allocate for the mounted file system info.  */
732     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
733       return NULL;
734     entries = xmalloc (bufsize);
736     /* Get the list of mounted file systems.  */
737     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
738     if (n_entries < 0)
739       {
740         int saved_errno = errno;
741         free (entries);
742         errno = saved_errno;
743         return NULL;
744       }
746     for (i = 0, thisent = entries;
747          i < n_entries;
748          i++, thisent += vmp->vmt_length)
749       {
750         char *options, *ignore;
752         vmp = (struct vmount *) thisent;
753         me = xmalloc (sizeof *me);
754         if (vmp->vmt_flags & MNT_REMOTE)
755           {
756             char *host, *dir;
758             me->me_remote = 1;
759             /* Prepend the remote dirname.  */
760             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
761             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
762             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
763             strcpy (me->me_devname, host);
764             strcat (me->me_devname, ":");
765             strcat (me->me_devname, dir);
766           }
767         else
768           {
769             me->me_remote = 0;
770             me->me_devname = xstrdup (thisent +
771                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
772           }
773         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
774         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
775         me->me_type_malloced = 1;
776         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
777         ignore = strstr (options, "ignore");
778         me->me_dummy = (ignore
779                         && (ignore == options || ignore[-1] == ',')
780                         && (ignore[sizeof "ignore" - 1] == ','
781                             || ignore[sizeof "ignore" - 1] == '\0'));
782         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
784         /* Add to the linked list. */
785         *mtail = me;
786         mtail = &me->me_next;
787       }
788     free (entries);
789   }
790 #endif /* MOUNTED_VMOUNT. */
792   *mtail = NULL;
793   return mount_list;
796  free_then_fail:
797   {
798     int saved_errno = errno;
799     *mtail = NULL;
801     while (mount_list)
802       {
803         me = mount_list->me_next;
804         free (mount_list->me_devname);
805         free (mount_list->me_mountdir);
806         if (mount_list->me_type_malloced)
807           free (mount_list->me_type);
808         free (mount_list);
809         mount_list = me;
810       }
812     errno = saved_errno;
813     return NULL;
814   }