Code

50e90eed473253e4be76068808ba7161bbd67c67
[nagiosplug.git] / gl / mountlist.c
1 /* mountlist.c -- return a list of mounted file systems
3    Copyright (C) 1991, 1992, 1997-2009 Free Software Foundation, Inc.
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 #include <config.h>
20 #include "mountlist.h"
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
28 #include "xalloc.h"
30 #include <errno.h>
32 #include <fcntl.h>
34 #include <unistd.h>
36 #if HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
40 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
41 # if HAVE_SYS_UCRED_H
42 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
43                       NGROUPS is used as an array dimension in ucred.h */
44 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
45 # endif
46 # if HAVE_SYS_MOUNT_H
47 #  include <sys/mount.h>
48 # endif
49 # if HAVE_SYS_FS_TYPES_H
50 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
51 # endif
52 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
53 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
54 # else
55 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
56 # endif
57 #endif /* MOUNTED_GETFSSTAT */
59 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
60 # include <mntent.h>
61 # if !defined MOUNTED
62 #  if defined _PATH_MOUNTED     /* GNU libc  */
63 #   define MOUNTED _PATH_MOUNTED
64 #  endif
65 #  if defined MNT_MNTTAB        /* HP-UX.  */
66 #   define MOUNTED MNT_MNTTAB
67 #  endif
68 #  if defined MNTTABNAME        /* Dynix.  */
69 #   define MOUNTED MNTTABNAME
70 #  endif
71 # endif
72 #endif
74 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
75 # include <sys/mount.h>
76 #endif
78 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
79 # include <sys/statvfs.h>
80 #endif
82 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
83 # include <sys/mount.h>
84 # include <sys/fs_types.h>
85 #endif
87 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
88 # include <fs_info.h>
89 # include <dirent.h>
90 #endif
92 #ifdef MOUNTED_FREAD            /* SVR2.  */
93 # include <mnttab.h>
94 #endif
96 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
97 # include <mnttab.h>
98 # include <sys/fstyp.h>
99 # include <sys/statfs.h>
100 #endif
102 #ifdef MOUNTED_LISTMNTENT
103 # include <mntent.h>
104 #endif
106 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
107 # include <sys/mnttab.h>
108 #endif
110 #ifdef MOUNTED_VMOUNT           /* AIX.  */
111 # include <fshelp.h>
112 # include <sys/vfs.h>
113 #endif
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
121 #if HAVE_SYS_MNTENT_H
122 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
123 # include <sys/mntent.h>
124 #endif
126 #undef MNT_IGNORE
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
133 #if USE_UNLOCKED_IO
134 # include "unlocked-io.h"
135 #endif
137 /* The results of open() in this file are not used with fchdir,
138    therefore save some unnecessary work in fchdir.c.  */
139 #undef open
140 #undef close
142 /* The results of opendir() in this file are not used with dirfd and fchdir,
143    therefore save some unnecessary work in fchdir.c.  */
144 #undef opendir
145 #undef closedir
147 #ifndef ME_DUMMY
148 # define ME_DUMMY(Fs_name, Fs_type)             \
149     (strcmp (Fs_type, "autofs") == 0            \
150      || strcmp (Fs_type, "none") == 0           \
151      || strcmp (Fs_type, "proc") == 0           \
152      || strcmp (Fs_type, "subfs") == 0          \
153      /* for NetBSD 3.0 */                       \
154      || strcmp (Fs_type, "kernfs") == 0         \
155      /* for Irix 6.5 */                         \
156      || strcmp (Fs_type, "ignore") == 0)
157 #endif
159 #ifndef ME_REMOTE
160 /* A file system is `remote' if its Fs_name contains a `:'
161    or if (it is of type (smbfs or cifs) and its Fs_name starts with `//').  */
162 # define ME_REMOTE(Fs_name, Fs_type)            \
163     (strchr (Fs_name, ':') != NULL              \
164      || ((Fs_name)[0] == '/'                    \
165          && (Fs_name)[1] == '/'                 \
166          && (strcmp (Fs_type, "smbfs") == 0     \
167              || strcmp (Fs_type, "cifs") == 0)))
168 #endif
170 #if MOUNTED_GETMNTINFO
172 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
173 static char *
174 fstype_to_string (short int t)
176   switch (t)
177     {
178 #  ifdef MOUNT_PC
179     case MOUNT_PC:
180       return "pc";
181 #  endif
182 #  ifdef MOUNT_MFS
183     case MOUNT_MFS:
184       return "mfs";
185 #  endif
186 #  ifdef MOUNT_LO
187     case MOUNT_LO:
188       return "lo";
189 #  endif
190 #  ifdef MOUNT_TFS
191     case MOUNT_TFS:
192       return "tfs";
193 #  endif
194 #  ifdef MOUNT_TMP
195     case MOUNT_TMP:
196       return "tmp";
197 #  endif
198 #  ifdef MOUNT_UFS
199    case MOUNT_UFS:
200      return "ufs" ;
201 #  endif
202 #  ifdef MOUNT_NFS
203    case MOUNT_NFS:
204      return "nfs" ;
205 #  endif
206 #  ifdef MOUNT_MSDOS
207    case MOUNT_MSDOS:
208      return "msdos" ;
209 #  endif
210 #  ifdef MOUNT_LFS
211    case MOUNT_LFS:
212      return "lfs" ;
213 #  endif
214 #  ifdef MOUNT_LOFS
215    case MOUNT_LOFS:
216      return "lofs" ;
217 #  endif
218 #  ifdef MOUNT_FDESC
219    case MOUNT_FDESC:
220      return "fdesc" ;
221 #  endif
222 #  ifdef MOUNT_PORTAL
223    case MOUNT_PORTAL:
224      return "portal" ;
225 #  endif
226 #  ifdef MOUNT_NULL
227    case MOUNT_NULL:
228      return "null" ;
229 #  endif
230 #  ifdef MOUNT_UMAP
231    case MOUNT_UMAP:
232      return "umap" ;
233 #  endif
234 #  ifdef MOUNT_KERNFS
235    case MOUNT_KERNFS:
236      return "kernfs" ;
237 #  endif
238 #  ifdef MOUNT_PROCFS
239    case MOUNT_PROCFS:
240      return "procfs" ;
241 #  endif
242 #  ifdef MOUNT_AFS
243    case MOUNT_AFS:
244      return "afs" ;
245 #  endif
246 #  ifdef MOUNT_CD9660
247    case MOUNT_CD9660:
248      return "cd9660" ;
249 #  endif
250 #  ifdef MOUNT_UNION
251    case MOUNT_UNION:
252      return "union" ;
253 #  endif
254 #  ifdef MOUNT_DEVFS
255    case MOUNT_DEVFS:
256      return "devfs" ;
257 #  endif
258 #  ifdef MOUNT_EXT2FS
259    case MOUNT_EXT2FS:
260      return "ext2fs" ;
261 #  endif
262     default:
263       return "?";
264     }
266 # endif
268 static char *
269 fsp_to_string (const struct statfs *fsp)
271 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
272   return (char *) (fsp->f_fstypename);
273 # else
274   return fstype_to_string (fsp->f_type);
275 # endif
278 #endif /* MOUNTED_GETMNTINFO */
280 #ifdef MOUNTED_VMOUNT           /* AIX.  */
281 static char *
282 fstype_to_string (int t)
284   struct vfs_ent *e;
286   e = getvfsbytype (t);
287   if (!e || !e->vfsent_name)
288     return "none";
289   else
290     return e->vfsent_name;
292 #endif /* MOUNTED_VMOUNT */
295 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
297 /* Return the device number from MOUNT_OPTIONS, if possible.
298    Otherwise return (dev_t) -1.  */
299 static dev_t
300 dev_from_mount_options (char const *mount_options)
302   /* GNU/Linux allows file system implementations to define their own
303      meaning for "dev=" mount options, so don't trust the meaning
304      here.  */
305 # ifndef __linux__
307   static char const dev_pattern[] = ",dev=";
308   char const *devopt = strstr (mount_options, dev_pattern);
310   if (devopt)
311     {
312       char const *optval = devopt + sizeof dev_pattern - 1;
313       char *optvalend;
314       unsigned long int dev;
315       errno = 0;
316       dev = strtoul (optval, &optvalend, 16);
317       if (optval != optvalend
318           && (*optvalend == '\0' || *optvalend == ',')
319           && ! (dev == ULONG_MAX && errno == ERANGE)
320           && dev == (dev_t) dev)
321         return dev;
322     }
324 # endif
325   (void) mount_options;
326   return -1;
329 #endif
331 /* Return a list of the currently mounted file systems, or NULL on error.
332    Add each entry to the tail of the list so that they stay in order.
333    If NEED_FS_TYPE is true, ensure that the file system type fields in
334    the returned list are valid.  Otherwise, they might not be.  */
336 struct mount_entry *
337 read_file_system_list (bool need_fs_type)
339   struct mount_entry *mount_list;
340   struct mount_entry *me;
341   struct mount_entry **mtail = &mount_list;
342   (void) need_fs_type;
344 #ifdef MOUNTED_LISTMNTENT
345   {
346     struct tabmntent *mntlist, *p;
347     struct mntent *mnt;
348     struct mount_entry *me;
350     /* the third and fourth arguments could be used to filter mounts,
351        but Crays doesn't seem to have any mounts that we want to
352        remove. Specifically, automount create normal NFS mounts.
353        */
355     if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
356       return NULL;
357     for (p = mntlist; p; p = p->next) {
358       mnt = p->ment;
359       me = xmalloc (sizeof *me);
360       me->me_devname = xstrdup (mnt->mnt_fsname);
361       me->me_mountdir = xstrdup (mnt->mnt_dir);
362       me->me_type = xstrdup (mnt->mnt_type);
363       me->me_type_malloced = 1;
364       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
365       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
366       me->me_dev = -1;
367       *mtail = me;
368       mtail = &me->me_next;
369     }
370     freemntlist (mntlist);
371   }
372 #endif
374 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
375   {
376     struct mntent *mnt;
377     char const *table = MOUNTED;
378     FILE *fp;
380     fp = setmntent (table, "r");
381     if (fp == NULL)
382       return NULL;
384     while ((mnt = getmntent (fp)))
385       {
386         me = xmalloc (sizeof *me);
387         me->me_devname = xstrdup (mnt->mnt_fsname);
388         me->me_mountdir = xstrdup (mnt->mnt_dir);
389         me->me_type = xstrdup (mnt->mnt_type);
390         me->me_type_malloced = 1;
391         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
392         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
393         me->me_dev = dev_from_mount_options (mnt->mnt_opts);
395         /* Add to the linked list. */
396         *mtail = me;
397         mtail = &me->me_next;
398       }
400     if (endmntent (fp) == 0)
401       goto free_then_fail;
402   }
403 #endif /* MOUNTED_GETMNTENT1. */
405 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
406   {
407     struct statfs *fsp;
408     int entries;
410     entries = getmntinfo (&fsp, MNT_NOWAIT);
411     if (entries < 0)
412       return NULL;
413     for (; entries-- > 0; fsp++)
414       {
415         char *fs_type = fsp_to_string (fsp);
417         me = xmalloc (sizeof *me);
418         me->me_devname = xstrdup (fsp->f_mntfromname);
419         me->me_mountdir = xstrdup (fsp->f_mntonname);
420         me->me_type = fs_type;
421         me->me_type_malloced = 0;
422         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
423         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
424         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
426         /* Add to the linked list. */
427         *mtail = me;
428         mtail = &me->me_next;
429       }
430   }
431 #endif /* MOUNTED_GETMNTINFO */
433 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
434   {
435     struct statvfs *fsp;
436     int entries;
438     entries = getmntinfo (&fsp, MNT_NOWAIT);
439     if (entries < 0)
440       return NULL;
441     for (; entries-- > 0; fsp++)
442       {
443         me = xmalloc (sizeof *me);
444         me->me_devname = xstrdup (fsp->f_mntfromname);
445         me->me_mountdir = xstrdup (fsp->f_mntonname);
446         me->me_type = xstrdup (fsp->f_fstypename);
447         me->me_type_malloced = 1;
448         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
449         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
450         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
452         /* Add to the linked list. */
453         *mtail = me;
454         mtail = &me->me_next;
455       }
456   }
457 #endif /* MOUNTED_GETMNTINFO2 */
459 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
460   {
461     int offset = 0;
462     int val;
463     struct fs_data fsd;
465     while (errno = 0,
466            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
467                               (char *) 0)))
468       {
469         me = xmalloc (sizeof *me);
470         me->me_devname = xstrdup (fsd.fd_req.devname);
471         me->me_mountdir = xstrdup (fsd.fd_req.path);
472         me->me_type = gt_names[fsd.fd_req.fstype];
473         me->me_type_malloced = 0;
474         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
475         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
476         me->me_dev = fsd.fd_req.dev;
478         /* Add to the linked list. */
479         *mtail = me;
480         mtail = &me->me_next;
481       }
482     if (val < 0)
483       goto free_then_fail;
484   }
485 #endif /* MOUNTED_GETMNT. */
487 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
488   {
489     /* The next_dev() and fs_stat_dev() system calls give the list of
490        all file systems, including the information returned by statvfs()
491        (fs type, total blocks, free blocks etc.), but without the mount
492        point. But on BeOS all file systems except / are mounted in the
493        rootfs, directly under /.
494        The directory name of the mount point is often, but not always,
495        identical to the volume name of the device.
496        We therefore get the list of subdirectories of /, and the list
497        of all file systems, and match the two lists.  */
499     DIR *dirp;
500     struct rootdir_entry
501       {
502         char *name;
503         dev_t dev;
504         ino_t ino;
505         struct rootdir_entry *next;
506       };
507     struct rootdir_entry *rootdir_list;
508     struct rootdir_entry **rootdir_tail;
509     int32 pos;
510     dev_t dev;
511     fs_info fi;
513     /* All volumes are mounted in the rootfs, directly under /. */
514     rootdir_list = NULL;
515     rootdir_tail = &rootdir_list;
516     dirp = opendir ("/");
517     if (dirp)
518       {
519         struct dirent *d;
521         while ((d = readdir (dirp)) != NULL)
522           {
523             char *name;
524             struct stat statbuf;
526             if (strcmp (d->d_name, "..") == 0)
527               continue;
529             if (strcmp (d->d_name, ".") == 0)
530               name = xstrdup ("/");
531             else
532               {
533                 name = xmalloc (1 + strlen (d->d_name) + 1);
534                 name[0] = '/';
535                 strcpy (name + 1, d->d_name);
536               }
538             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
539               {
540                 struct rootdir_entry *re = xmalloc (sizeof *re);
541                 re->name = name;
542                 re->dev = statbuf.st_dev;
543                 re->ino = statbuf.st_ino;
545                 /* Add to the linked list.  */
546                 *rootdir_tail = re;
547                 rootdir_tail = &re->next;
548               }
549             else
550               free (name);
551           }
552         closedir (dirp);
553       }
554     *rootdir_tail = NULL;
556     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
557       if (fs_stat_dev (dev, &fi) >= 0)
558         {
559           /* Note: fi.dev == dev. */
560           struct rootdir_entry *re;
562           for (re = rootdir_list; re; re = re->next)
563             if (re->dev == fi.dev && re->ino == fi.root)
564               break;
566           me = xmalloc (sizeof *me);
567           me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
568           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
569           me->me_type = xstrdup (fi.fsh_name);
570           me->me_type_malloced = 1;
571           me->me_dev = fi.dev;
572           me->me_dummy = 0;
573           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
575           /* Add to the linked list. */
576           *mtail = me;
577           mtail = &me->me_next;
578         }
579     *mtail = NULL;
581     while (rootdir_list != NULL)
582       {
583         struct rootdir_entry *re = rootdir_list;
584         rootdir_list = re->next;
585         free (re->name);
586         free (re);
587       }
588   }
589 #endif /* MOUNTED_FS_STAT_DEV */
591 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
592   {
593     int numsys, counter;
594     size_t bufsize;
595     struct statfs *stats;
597     numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
598     if (numsys < 0)
599       return (NULL);
600     if (SIZE_MAX / sizeof *stats <= numsys)
601       xalloc_die ();
603     bufsize = (1 + numsys) * sizeof *stats;
604     stats = xmalloc (bufsize);
605     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
607     if (numsys < 0)
608       {
609         free (stats);
610         return (NULL);
611       }
613     for (counter = 0; counter < numsys; counter++)
614       {
615         me = xmalloc (sizeof *me);
616         me->me_devname = xstrdup (stats[counter].f_mntfromname);
617         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
618         me->me_type = xstrdup (FS_TYPE (stats[counter]));
619         me->me_type_malloced = 1;
620         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
621         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
622         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
624         /* Add to the linked list. */
625         *mtail = me;
626         mtail = &me->me_next;
627       }
629     free (stats);
630   }
631 #endif /* MOUNTED_GETFSSTAT */
633 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
634   {
635     struct mnttab mnt;
636     char *table = "/etc/mnttab";
637     FILE *fp;
639     fp = fopen (table, "r");
640     if (fp == NULL)
641       return NULL;
643     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
644       {
645         me = xmalloc (sizeof *me);
646 # ifdef GETFSTYP                        /* SVR3.  */
647         me->me_devname = xstrdup (mnt.mt_dev);
648 # else
649         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
650         strcpy (me->me_devname, "/dev/");
651         strcpy (me->me_devname + 5, mnt.mt_dev);
652 # endif
653         me->me_mountdir = xstrdup (mnt.mt_filsys);
654         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
655         me->me_type = "";
656         me->me_type_malloced = 0;
657 # ifdef GETFSTYP                        /* SVR3.  */
658         if (need_fs_type)
659           {
660             struct statfs fsd;
661             char typebuf[FSTYPSZ];
663             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
664                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
665               {
666                 me->me_type = xstrdup (typebuf);
667                 me->me_type_malloced = 1;
668               }
669           }
670 # endif
671         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
672         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
674         /* Add to the linked list. */
675         *mtail = me;
676         mtail = &me->me_next;
677       }
679     if (ferror (fp))
680       {
681         /* The last fread() call must have failed.  */
682         int saved_errno = errno;
683         fclose (fp);
684         errno = saved_errno;
685         goto free_then_fail;
686       }
688     if (fclose (fp) == EOF)
689       goto free_then_fail;
690   }
691 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
693 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes its own way.  */
694   {
695     struct mntent **mnttbl = getmnttbl (), **ent;
696     for (ent=mnttbl;*ent;ent++)
697       {
698         me = xmalloc (sizeof *me);
699         me->me_devname = xstrdup ( (*ent)->mt_resource);
700         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
701         me->me_type = xstrdup ((*ent)->mt_fstype);
702         me->me_type_malloced = 1;
703         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
704         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
705         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
707         /* Add to the linked list. */
708         *mtail = me;
709         mtail = &me->me_next;
710       }
711     endmnttbl ();
712   }
713 #endif
715 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
716   {
717     struct mnttab mnt;
718     char *table = MNTTAB;
719     FILE *fp;
720     int ret;
721     int lockfd = -1;
723 # if defined F_RDLCK && defined F_SETLKW
724     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
725        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
726        for this file name, we should use their macro name instead.
727        (Why not just lock MNTTAB directly?  We don't know.)  */
728 #  ifndef MNTTAB_LOCK
729 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
730 #  endif
731     lockfd = open (MNTTAB_LOCK, O_RDONLY);
732     if (0 <= lockfd)
733       {
734         struct flock flock;
735         flock.l_type = F_RDLCK;
736         flock.l_whence = SEEK_SET;
737         flock.l_start = 0;
738         flock.l_len = 0;
739         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
740           if (errno != EINTR)
741             {
742               int saved_errno = errno;
743               close (lockfd);
744               errno = saved_errno;
745               return NULL;
746             }
747       }
748     else if (errno != ENOENT)
749       return NULL;
750 # endif
752     errno = 0;
753     fp = fopen (table, "r");
754     if (fp == NULL)
755       ret = errno;
756     else
757       {
758         while ((ret = getmntent (fp, &mnt)) == 0)
759           {
760             me = xmalloc (sizeof *me);
761             me->me_devname = xstrdup (mnt.mnt_special);
762             me->me_mountdir = xstrdup (mnt.mnt_mountp);
763             me->me_type = xstrdup (mnt.mnt_fstype);
764             me->me_type_malloced = 1;
765             me->me_dummy = MNT_IGNORE (&mnt) != 0;
766             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
767             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
769             /* Add to the linked list. */
770             *mtail = me;
771             mtail = &me->me_next;
772           }
774         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
775       }
777     if (0 <= lockfd && close (lockfd) != 0)
778       ret = errno;
780     if (0 <= ret)
781       {
782         errno = ret;
783         goto free_then_fail;
784       }
785   }
786 #endif /* MOUNTED_GETMNTENT2.  */
788 #ifdef MOUNTED_VMOUNT           /* AIX.  */
789   {
790     int bufsize;
791     char *entries, *thisent;
792     struct vmount *vmp;
793     int n_entries;
794     int i;
796     /* Ask how many bytes to allocate for the mounted file system info.  */
797     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
798       return NULL;
799     entries = xmalloc (bufsize);
801     /* Get the list of mounted file systems.  */
802     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
803     if (n_entries < 0)
804       {
805         int saved_errno = errno;
806         free (entries);
807         errno = saved_errno;
808         return NULL;
809       }
811     for (i = 0, thisent = entries;
812          i < n_entries;
813          i++, thisent += vmp->vmt_length)
814       {
815         char *options, *ignore;
817         vmp = (struct vmount *) thisent;
818         me = xmalloc (sizeof *me);
819         if (vmp->vmt_flags & MNT_REMOTE)
820           {
821             char *host, *dir;
823             me->me_remote = 1;
824             /* Prepend the remote dirname.  */
825             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
826             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
827             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
828             strcpy (me->me_devname, host);
829             strcat (me->me_devname, ":");
830             strcat (me->me_devname, dir);
831           }
832         else
833           {
834             me->me_remote = 0;
835             me->me_devname = xstrdup (thisent +
836                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
837           }
838         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
839         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
840         me->me_type_malloced = 1;
841         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
842         ignore = strstr (options, "ignore");
843         me->me_dummy = (ignore
844                         && (ignore == options || ignore[-1] == ',')
845                         && (ignore[sizeof "ignore" - 1] == ','
846                             || ignore[sizeof "ignore" - 1] == '\0'));
847         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
849         /* Add to the linked list. */
850         *mtail = me;
851         mtail = &me->me_next;
852       }
853     free (entries);
854   }
855 #endif /* MOUNTED_VMOUNT. */
857   *mtail = NULL;
858   return mount_list;
861  free_then_fail:
862   {
863     int saved_errno = errno;
864     *mtail = NULL;
866     while (mount_list)
867       {
868         me = mount_list->me_next;
869         free (mount_list->me_devname);
870         free (mount_list->me_mountdir);
871         if (mount_list->me_type_malloced)
872           free (mount_list->me_type);
873         free (mount_list);
874         mount_list = me;
875       }
877     errno = saved_errno;
878     return NULL;
879   }