Code

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