Back to index

nagios-plugins  1.4.16
mountlist.c
Go to the documentation of this file.
00001 /* mountlist.c -- return a list of mounted file systems
00002 
00003    Copyright (C) 1991-1992, 1997-2010 Free Software Foundation, Inc.
00004 
00005    This program is free software: you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 3 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00017 
00018 #include <config.h>
00019 
00020 #include "mountlist.h"
00021 
00022 #include <limits.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <stdint.h>
00027 
00028 #include "xalloc.h"
00029 
00030 #include <errno.h>
00031 
00032 #include <fcntl.h>
00033 
00034 #include <unistd.h>
00035 
00036 #if HAVE_SYS_PARAM_H
00037 # include <sys/param.h>
00038 #endif
00039 
00040 #if defined MOUNTED_GETFSSTAT   /* OSF_1 and Darwin1.3.x */
00041 # if HAVE_SYS_UCRED_H
00042 #  include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS,
00043                       NGROUPS is used as an array dimension in ucred.h */
00044 #  include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */
00045 # endif
00046 # if HAVE_SYS_MOUNT_H
00047 #  include <sys/mount.h>
00048 # endif
00049 # if HAVE_SYS_FS_TYPES_H
00050 #  include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */
00051 # endif
00052 # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME
00053 #  define FS_TYPE(Ent) ((Ent).f_fstypename)
00054 # else
00055 #  define FS_TYPE(Ent) mnt_names[(Ent).f_type]
00056 # endif
00057 #endif /* MOUNTED_GETFSSTAT */
00058 
00059 #ifdef MOUNTED_GETMNTENT1       /* 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
00060 # include <mntent.h>
00061 # if !defined MOUNTED
00062 #  if defined _PATH_MOUNTED     /* GNU libc  */
00063 #   define MOUNTED _PATH_MOUNTED
00064 #  endif
00065 #  if defined MNT_MNTTAB        /* HP-UX.  */
00066 #   define MOUNTED MNT_MNTTAB
00067 #  endif
00068 #  if defined MNTTABNAME        /* Dynix.  */
00069 #   define MOUNTED MNTTABNAME
00070 #  endif
00071 # endif
00072 #endif
00073 
00074 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
00075 # include <sys/mount.h>
00076 #endif
00077 
00078 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
00079 # include <sys/statvfs.h>
00080 #endif
00081 
00082 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
00083 # include <sys/mount.h>
00084 # include <sys/fs_types.h>
00085 #endif
00086 
00087 #ifdef MOUNTED_FS_STAT_DEV      /* BeOS.  */
00088 # include <fs_info.h>
00089 # include <dirent.h>
00090 #endif
00091 
00092 #ifdef MOUNTED_FREAD            /* SVR2.  */
00093 # include <mnttab.h>
00094 #endif
00095 
00096 #ifdef MOUNTED_FREAD_FSTYP      /* SVR3.  */
00097 # include <mnttab.h>
00098 # include <sys/fstyp.h>
00099 # include <sys/statfs.h>
00100 #endif
00101 
00102 #ifdef MOUNTED_LISTMNTENT
00103 # include <mntent.h>
00104 #endif
00105 
00106 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
00107 # include <sys/mnttab.h>
00108 #endif
00109 
00110 #ifdef MOUNTED_VMOUNT           /* AIX.  */
00111 # include <fshelp.h>
00112 # include <sys/vfs.h>
00113 #endif
00114 
00115 #ifdef DOLPHIN
00116 /* So special that it's not worth putting this in autoconf.  */
00117 # undef MOUNTED_FREAD_FSTYP
00118 # define MOUNTED_GETMNTTBL
00119 #endif
00120 
00121 #if HAVE_SYS_MNTENT_H
00122 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
00123 # include <sys/mntent.h>
00124 #endif
00125 
00126 #undef MNT_IGNORE
00127 #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT
00128 # define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
00129 #else
00130 # define MNT_IGNORE(M) 0
00131 #endif
00132 
00133 #if USE_UNLOCKED_IO
00134 # include "unlocked-io.h"
00135 #endif
00136 
00137 /* The results of open() in this file are not used with fchdir,
00138    therefore save some unnecessary work in fchdir.c.  */
00139 #undef open
00140 #undef close
00141 
00142 /* The results of opendir() in this file are not used with dirfd and fchdir,
00143    therefore save some unnecessary work in fchdir.c.  */
00144 #undef opendir
00145 #undef closedir
00146 
00147 #ifndef ME_DUMMY
00148 # define ME_DUMMY(Fs_name, Fs_type)             \
00149     (strcmp (Fs_type, "autofs") == 0            \
00150      || strcmp (Fs_type, "none") == 0           \
00151      || strcmp (Fs_type, "proc") == 0           \
00152      || strcmp (Fs_type, "subfs") == 0          \
00153      /* for NetBSD 3.0 */                       \
00154      || strcmp (Fs_type, "kernfs") == 0         \
00155      /* for Irix 6.5 */                         \
00156      || strcmp (Fs_type, "ignore") == 0)
00157 #endif
00158 
00159 #ifndef ME_REMOTE
00160 /* A file system is `remote' if its Fs_name contains a `:'
00161    or if (it is of type (smbfs or cifs) and its Fs_name starts with `//').  */
00162 # define ME_REMOTE(Fs_name, Fs_type)            \
00163     (strchr (Fs_name, ':') != NULL              \
00164      || ((Fs_name)[0] == '/'                    \
00165          && (Fs_name)[1] == '/'                 \
00166          && (strcmp (Fs_type, "smbfs") == 0     \
00167              || strcmp (Fs_type, "cifs") == 0)))
00168 #endif
00169 
00170 #if MOUNTED_GETMNTINFO
00171 
00172 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
00173 static char *
00174 fstype_to_string (short int t)
00175 {
00176   switch (t)
00177     {
00178 #  ifdef MOUNT_PC
00179     case MOUNT_PC:
00180       return "pc";
00181 #  endif
00182 #  ifdef MOUNT_MFS
00183     case MOUNT_MFS:
00184       return "mfs";
00185 #  endif
00186 #  ifdef MOUNT_LO
00187     case MOUNT_LO:
00188       return "lo";
00189 #  endif
00190 #  ifdef MOUNT_TFS
00191     case MOUNT_TFS:
00192       return "tfs";
00193 #  endif
00194 #  ifdef MOUNT_TMP
00195     case MOUNT_TMP:
00196       return "tmp";
00197 #  endif
00198 #  ifdef MOUNT_UFS
00199    case MOUNT_UFS:
00200      return "ufs" ;
00201 #  endif
00202 #  ifdef MOUNT_NFS
00203    case MOUNT_NFS:
00204      return "nfs" ;
00205 #  endif
00206 #  ifdef MOUNT_MSDOS
00207    case MOUNT_MSDOS:
00208      return "msdos" ;
00209 #  endif
00210 #  ifdef MOUNT_LFS
00211    case MOUNT_LFS:
00212      return "lfs" ;
00213 #  endif
00214 #  ifdef MOUNT_LOFS
00215    case MOUNT_LOFS:
00216      return "lofs" ;
00217 #  endif
00218 #  ifdef MOUNT_FDESC
00219    case MOUNT_FDESC:
00220      return "fdesc" ;
00221 #  endif
00222 #  ifdef MOUNT_PORTAL
00223    case MOUNT_PORTAL:
00224      return "portal" ;
00225 #  endif
00226 #  ifdef MOUNT_NULL
00227    case MOUNT_NULL:
00228      return "null" ;
00229 #  endif
00230 #  ifdef MOUNT_UMAP
00231    case MOUNT_UMAP:
00232      return "umap" ;
00233 #  endif
00234 #  ifdef MOUNT_KERNFS
00235    case MOUNT_KERNFS:
00236      return "kernfs" ;
00237 #  endif
00238 #  ifdef MOUNT_PROCFS
00239    case MOUNT_PROCFS:
00240      return "procfs" ;
00241 #  endif
00242 #  ifdef MOUNT_AFS
00243    case MOUNT_AFS:
00244      return "afs" ;
00245 #  endif
00246 #  ifdef MOUNT_CD9660
00247    case MOUNT_CD9660:
00248      return "cd9660" ;
00249 #  endif
00250 #  ifdef MOUNT_UNION
00251    case MOUNT_UNION:
00252      return "union" ;
00253 #  endif
00254 #  ifdef MOUNT_DEVFS
00255    case MOUNT_DEVFS:
00256      return "devfs" ;
00257 #  endif
00258 #  ifdef MOUNT_EXT2FS
00259    case MOUNT_EXT2FS:
00260      return "ext2fs" ;
00261 #  endif
00262     default:
00263       return "?";
00264     }
00265 }
00266 # endif
00267 
00268 static char *
00269 fsp_to_string (const struct statfs *fsp)
00270 {
00271 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
00272   return (char *) (fsp->f_fstypename);
00273 # else
00274   return fstype_to_string (fsp->f_type);
00275 # endif
00276 }
00277 
00278 #endif /* MOUNTED_GETMNTINFO */
00279 
00280 #ifdef MOUNTED_VMOUNT           /* AIX.  */
00281 static char *
00282 fstype_to_string (int t)
00283 {
00284   struct vfs_ent *e;
00285 
00286   e = getvfsbytype (t);
00287   if (!e || !e->vfsent_name)
00288     return "none";
00289   else
00290     return e->vfsent_name;
00291 }
00292 #endif /* MOUNTED_VMOUNT */
00293 
00294 
00295 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
00296 
00297 /* Return the device number from MOUNT_OPTIONS, if possible.
00298    Otherwise return (dev_t) -1.  */
00299 static dev_t
00300 dev_from_mount_options (char const *mount_options)
00301 {
00302   /* GNU/Linux allows file system implementations to define their own
00303      meaning for "dev=" mount options, so don't trust the meaning
00304      here.  */
00305 # ifndef __linux__
00306 
00307   static char const dev_pattern[] = ",dev=";
00308   char const *devopt = strstr (mount_options, dev_pattern);
00309 
00310   if (devopt)
00311     {
00312       char const *optval = devopt + sizeof dev_pattern - 1;
00313       char *optvalend;
00314       unsigned long int dev;
00315       errno = 0;
00316       dev = strtoul (optval, &optvalend, 16);
00317       if (optval != optvalend
00318           && (*optvalend == '\0' || *optvalend == ',')
00319           && ! (dev == ULONG_MAX && errno == ERANGE)
00320           && dev == (dev_t) dev)
00321         return dev;
00322     }
00323 
00324 # endif
00325   (void) mount_options;
00326   return -1;
00327 }
00328 
00329 #endif
00330 
00331 /* Return a list of the currently mounted file systems, or NULL on error.
00332    Add each entry to the tail of the list so that they stay in order.
00333    If NEED_FS_TYPE is true, ensure that the file system type fields in
00334    the returned list are valid.  Otherwise, they might not be.  */
00335 
00336 struct mount_entry *
00337 read_file_system_list (bool need_fs_type)
00338 {
00339   struct mount_entry *mount_list;
00340   struct mount_entry *me;
00341   struct mount_entry **mtail = &mount_list;
00342   (void) need_fs_type;
00343 
00344 #ifdef MOUNTED_LISTMNTENT
00345   {
00346     struct tabmntent *mntlist, *p;
00347     struct mntent *mnt;
00348     struct mount_entry *me;
00349 
00350     /* the third and fourth arguments could be used to filter mounts,
00351        but Crays doesn't seem to have any mounts that we want to
00352        remove. Specifically, automount create normal NFS mounts.
00353        */
00354 
00355     if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0)
00356       return NULL;
00357     for (p = mntlist; p; p = p->next) {
00358       mnt = p->ment;
00359       me = xmalloc (sizeof *me);
00360       me->me_devname = xstrdup (mnt->mnt_fsname);
00361       me->me_mountdir = xstrdup (mnt->mnt_dir);
00362       me->me_type = xstrdup (mnt->mnt_type);
00363       me->me_type_malloced = 1;
00364       me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00365       me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00366       me->me_dev = -1;
00367       *mtail = me;
00368       mtail = &me->me_next;
00369     }
00370     freemntlist (mntlist);
00371   }
00372 #endif
00373 
00374 #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix.  */
00375   {
00376     struct mntent *mnt;
00377     char const *table = MOUNTED;
00378     FILE *fp;
00379 
00380     fp = setmntent (table, "r");
00381     if (fp == NULL)
00382       return NULL;
00383 
00384     while ((mnt = getmntent (fp)))
00385       {
00386         me = xmalloc (sizeof *me);
00387         me->me_devname = xstrdup (mnt->mnt_fsname);
00388         me->me_mountdir = xstrdup (mnt->mnt_dir);
00389         me->me_type = xstrdup (mnt->mnt_type);
00390         me->me_type_malloced = 1;
00391         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00392         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00393         me->me_dev = dev_from_mount_options (mnt->mnt_opts);
00394 
00395         /* Add to the linked list. */
00396         *mtail = me;
00397         mtail = &me->me_next;
00398       }
00399 
00400     if (endmntent (fp) == 0)
00401       goto free_then_fail;
00402   }
00403 #endif /* MOUNTED_GETMNTENT1. */
00404 
00405 #ifdef MOUNTED_GETMNTINFO       /* 4.4BSD.  */
00406   {
00407     struct statfs *fsp;
00408     int entries;
00409 
00410     entries = getmntinfo (&fsp, MNT_NOWAIT);
00411     if (entries < 0)
00412       return NULL;
00413     for (; entries-- > 0; fsp++)
00414       {
00415         char *fs_type = fsp_to_string (fsp);
00416 
00417         me = xmalloc (sizeof *me);
00418         me->me_devname = xstrdup (fsp->f_mntfromname);
00419         me->me_mountdir = xstrdup (fsp->f_mntonname);
00420         me->me_type = fs_type;
00421         me->me_type_malloced = 0;
00422         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00423         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00424         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
00425 
00426         /* Add to the linked list. */
00427         *mtail = me;
00428         mtail = &me->me_next;
00429       }
00430   }
00431 #endif /* MOUNTED_GETMNTINFO */
00432 
00433 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD 3.0.  */
00434   {
00435     struct statvfs *fsp;
00436     int entries;
00437 
00438     entries = getmntinfo (&fsp, MNT_NOWAIT);
00439     if (entries < 0)
00440       return NULL;
00441     for (; entries-- > 0; fsp++)
00442       {
00443         me = xmalloc (sizeof *me);
00444         me->me_devname = xstrdup (fsp->f_mntfromname);
00445         me->me_mountdir = xstrdup (fsp->f_mntonname);
00446         me->me_type = xstrdup (fsp->f_fstypename);
00447         me->me_type_malloced = 1;
00448         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00449         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00450         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
00451 
00452         /* Add to the linked list. */
00453         *mtail = me;
00454         mtail = &me->me_next;
00455       }
00456   }
00457 #endif /* MOUNTED_GETMNTINFO2 */
00458 
00459 #ifdef MOUNTED_GETMNT           /* Ultrix.  */
00460   {
00461     int offset = 0;
00462     int val;
00463     struct fs_data fsd;
00464 
00465     while (errno = 0,
00466            0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
00467                               (char *) 0)))
00468       {
00469         me = xmalloc (sizeof *me);
00470         me->me_devname = xstrdup (fsd.fd_req.devname);
00471         me->me_mountdir = xstrdup (fsd.fd_req.path);
00472         me->me_type = gt_names[fsd.fd_req.fstype];
00473         me->me_type_malloced = 0;
00474         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00475         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00476         me->me_dev = fsd.fd_req.dev;
00477 
00478         /* Add to the linked list. */
00479         *mtail = me;
00480         mtail = &me->me_next;
00481       }
00482     if (val < 0)
00483       goto free_then_fail;
00484   }
00485 #endif /* MOUNTED_GETMNT. */
00486 
00487 #if defined MOUNTED_FS_STAT_DEV /* BeOS */
00488   {
00489     /* The next_dev() and fs_stat_dev() system calls give the list of
00490        all file systems, including the information returned by statvfs()
00491        (fs type, total blocks, free blocks etc.), but without the mount
00492        point. But on BeOS all file systems except / are mounted in the
00493        rootfs, directly under /.
00494        The directory name of the mount point is often, but not always,
00495        identical to the volume name of the device.
00496        We therefore get the list of subdirectories of /, and the list
00497        of all file systems, and match the two lists.  */
00498 
00499     DIR *dirp;
00500     struct rootdir_entry
00501       {
00502         char *name;
00503         dev_t dev;
00504         ino_t ino;
00505         struct rootdir_entry *next;
00506       };
00507     struct rootdir_entry *rootdir_list;
00508     struct rootdir_entry **rootdir_tail;
00509     int32 pos;
00510     dev_t dev;
00511     fs_info fi;
00512 
00513     /* All volumes are mounted in the rootfs, directly under /. */
00514     rootdir_list = NULL;
00515     rootdir_tail = &rootdir_list;
00516     dirp = opendir ("/");
00517     if (dirp)
00518       {
00519         struct dirent *d;
00520 
00521         while ((d = readdir (dirp)) != NULL)
00522           {
00523             char *name;
00524             struct stat statbuf;
00525 
00526             if (strcmp (d->d_name, "..") == 0)
00527               continue;
00528 
00529             if (strcmp (d->d_name, ".") == 0)
00530               name = xstrdup ("/");
00531             else
00532               {
00533                 name = xmalloc (1 + strlen (d->d_name) + 1);
00534                 name[0] = '/';
00535                 strcpy (name + 1, d->d_name);
00536               }
00537 
00538             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
00539               {
00540                 struct rootdir_entry *re = xmalloc (sizeof *re);
00541                 re->name = name;
00542                 re->dev = statbuf.st_dev;
00543                 re->ino = statbuf.st_ino;
00544 
00545                 /* Add to the linked list.  */
00546                 *rootdir_tail = re;
00547                 rootdir_tail = &re->next;
00548               }
00549             else
00550               free (name);
00551           }
00552         closedir (dirp);
00553       }
00554     *rootdir_tail = NULL;
00555 
00556     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
00557       if (fs_stat_dev (dev, &fi) >= 0)
00558         {
00559           /* Note: fi.dev == dev. */
00560           struct rootdir_entry *re;
00561 
00562           for (re = rootdir_list; re; re = re->next)
00563             if (re->dev == fi.dev && re->ino == fi.root)
00564               break;
00565 
00566           me = xmalloc (sizeof *me);
00567           me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name);
00568           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
00569           me->me_type = xstrdup (fi.fsh_name);
00570           me->me_type_malloced = 1;
00571           me->me_dev = fi.dev;
00572           me->me_dummy = 0;
00573           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
00574 
00575           /* Add to the linked list. */
00576           *mtail = me;
00577           mtail = &me->me_next;
00578         }
00579     *mtail = NULL;
00580 
00581     while (rootdir_list != NULL)
00582       {
00583         struct rootdir_entry *re = rootdir_list;
00584         rootdir_list = re->next;
00585         free (re->name);
00586         free (re);
00587       }
00588   }
00589 #endif /* MOUNTED_FS_STAT_DEV */
00590 
00591 #if defined MOUNTED_GETFSSTAT   /* __alpha running OSF_1 */
00592   {
00593     int numsys, counter;
00594     size_t bufsize;
00595     struct statfs *stats;
00596 
00597     numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT);
00598     if (numsys < 0)
00599       return (NULL);
00600     if (SIZE_MAX / sizeof *stats <= numsys)
00601       xalloc_die ();
00602 
00603     bufsize = (1 + numsys) * sizeof *stats;
00604     stats = xmalloc (bufsize);
00605     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
00606 
00607     if (numsys < 0)
00608       {
00609         free (stats);
00610         return (NULL);
00611       }
00612 
00613     for (counter = 0; counter < numsys; counter++)
00614       {
00615         me = xmalloc (sizeof *me);
00616         me->me_devname = xstrdup (stats[counter].f_mntfromname);
00617         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
00618         me->me_type = xstrdup (FS_TYPE (stats[counter]));
00619         me->me_type_malloced = 1;
00620         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00621         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00622         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
00623 
00624         /* Add to the linked list. */
00625         *mtail = me;
00626         mtail = &me->me_next;
00627       }
00628 
00629     free (stats);
00630   }
00631 #endif /* MOUNTED_GETFSSTAT */
00632 
00633 #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23].  */
00634   {
00635     struct mnttab mnt;
00636     char *table = "/etc/mnttab";
00637     FILE *fp;
00638 
00639     fp = fopen (table, "r");
00640     if (fp == NULL)
00641       return NULL;
00642 
00643     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
00644       {
00645         me = xmalloc (sizeof *me);
00646 # ifdef GETFSTYP                        /* SVR3.  */
00647         me->me_devname = xstrdup (mnt.mt_dev);
00648 # else
00649         me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6);
00650         strcpy (me->me_devname, "/dev/");
00651         strcpy (me->me_devname + 5, mnt.mt_dev);
00652 # endif
00653         me->me_mountdir = xstrdup (mnt.mt_filsys);
00654         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
00655         me->me_type = "";
00656         me->me_type_malloced = 0;
00657 # ifdef GETFSTYP                        /* SVR3.  */
00658         if (need_fs_type)
00659           {
00660             struct statfs fsd;
00661             char typebuf[FSTYPSZ];
00662 
00663             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
00664                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
00665               {
00666                 me->me_type = xstrdup (typebuf);
00667                 me->me_type_malloced = 1;
00668               }
00669           }
00670 # endif
00671         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00672         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00673 
00674         /* Add to the linked list. */
00675         *mtail = me;
00676         mtail = &me->me_next;
00677       }
00678 
00679     if (ferror (fp))
00680       {
00681         /* The last fread() call must have failed.  */
00682         int saved_errno = errno;
00683         fclose (fp);
00684         errno = saved_errno;
00685         goto free_then_fail;
00686       }
00687 
00688     if (fclose (fp) == EOF)
00689       goto free_then_fail;
00690   }
00691 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP.  */
00692 
00693 #ifdef MOUNTED_GETMNTTBL        /* DolphinOS goes its own way.  */
00694   {
00695     struct mntent **mnttbl = getmnttbl (), **ent;
00696     for (ent=mnttbl;*ent;ent++)
00697       {
00698         me = xmalloc (sizeof *me);
00699         me->me_devname = xstrdup ( (*ent)->mt_resource);
00700         me->me_mountdir = xstrdup ( (*ent)->mt_directory);
00701         me->me_type = xstrdup ((*ent)->mt_fstype);
00702         me->me_type_malloced = 1;
00703         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
00704         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00705         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
00706 
00707         /* Add to the linked list. */
00708         *mtail = me;
00709         mtail = &me->me_next;
00710       }
00711     endmnttbl ();
00712   }
00713 #endif
00714 
00715 #ifdef MOUNTED_GETMNTENT2       /* SVR4.  */
00716   {
00717     struct mnttab mnt;
00718     char *table = MNTTAB;
00719     FILE *fp;
00720     int ret;
00721     int lockfd = -1;
00722 
00723 # if defined F_RDLCK && defined F_SETLKW
00724     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
00725        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
00726        for this file name, we should use their macro name instead.
00727        (Why not just lock MNTTAB directly?  We don't know.)  */
00728 #  ifndef MNTTAB_LOCK
00729 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
00730 #  endif
00731     lockfd = open (MNTTAB_LOCK, O_RDONLY);
00732     if (0 <= lockfd)
00733       {
00734         struct flock flock;
00735         flock.l_type = F_RDLCK;
00736         flock.l_whence = SEEK_SET;
00737         flock.l_start = 0;
00738         flock.l_len = 0;
00739         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
00740           if (errno != EINTR)
00741             {
00742               int saved_errno = errno;
00743               close (lockfd);
00744               errno = saved_errno;
00745               return NULL;
00746             }
00747       }
00748     else if (errno != ENOENT)
00749       return NULL;
00750 # endif
00751 
00752     errno = 0;
00753     fp = fopen (table, "r");
00754     if (fp == NULL)
00755       ret = errno;
00756     else
00757       {
00758         while ((ret = getmntent (fp, &mnt)) == 0)
00759           {
00760             me = xmalloc (sizeof *me);
00761             me->me_devname = xstrdup (mnt.mnt_special);
00762             me->me_mountdir = xstrdup (mnt.mnt_mountp);
00763             me->me_type = xstrdup (mnt.mnt_fstype);
00764             me->me_type_malloced = 1;
00765             me->me_dummy = MNT_IGNORE (&mnt) != 0;
00766             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
00767             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
00768 
00769             /* Add to the linked list. */
00770             *mtail = me;
00771             mtail = &me->me_next;
00772           }
00773 
00774         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
00775       }
00776 
00777     if (0 <= lockfd && close (lockfd) != 0)
00778       ret = errno;
00779 
00780     if (0 <= ret)
00781       {
00782         errno = ret;
00783         goto free_then_fail;
00784       }
00785   }
00786 #endif /* MOUNTED_GETMNTENT2.  */
00787 
00788 #ifdef MOUNTED_VMOUNT           /* AIX.  */
00789   {
00790     int bufsize;
00791     char *entries, *thisent;
00792     struct vmount *vmp;
00793     int n_entries;
00794     int i;
00795 
00796     /* Ask how many bytes to allocate for the mounted file system info.  */
00797     if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0)
00798       return NULL;
00799     entries = xmalloc (bufsize);
00800 
00801     /* Get the list of mounted file systems.  */
00802     n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
00803     if (n_entries < 0)
00804       {
00805         int saved_errno = errno;
00806         free (entries);
00807         errno = saved_errno;
00808         return NULL;
00809       }
00810 
00811     for (i = 0, thisent = entries;
00812          i < n_entries;
00813          i++, thisent += vmp->vmt_length)
00814       {
00815         char *options, *ignore;
00816 
00817         vmp = (struct vmount *) thisent;
00818         me = xmalloc (sizeof *me);
00819         if (vmp->vmt_flags & MNT_REMOTE)
00820           {
00821             char *host, *dir;
00822 
00823             me->me_remote = 1;
00824             /* Prepend the remote dirname.  */
00825             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
00826             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
00827             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
00828             strcpy (me->me_devname, host);
00829             strcat (me->me_devname, ":");
00830             strcat (me->me_devname, dir);
00831           }
00832         else
00833           {
00834             me->me_remote = 0;
00835             me->me_devname = xstrdup (thisent +
00836                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
00837           }
00838         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
00839         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
00840         me->me_type_malloced = 1;
00841         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
00842         ignore = strstr (options, "ignore");
00843         me->me_dummy = (ignore
00844                         && (ignore == options || ignore[-1] == ',')
00845                         && (ignore[sizeof "ignore" - 1] == ','
00846                             || ignore[sizeof "ignore" - 1] == '\0'));
00847         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
00848 
00849         /* Add to the linked list. */
00850         *mtail = me;
00851         mtail = &me->me_next;
00852       }
00853     free (entries);
00854   }
00855 #endif /* MOUNTED_VMOUNT. */
00856 
00857   *mtail = NULL;
00858   return mount_list;
00859 
00860 
00861  free_then_fail:
00862   {
00863     int saved_errno = errno;
00864     *mtail = NULL;
00865 
00866     while (mount_list)
00867       {
00868         me = mount_list->me_next;
00869         free (mount_list->me_devname);
00870         free (mount_list->me_mountdir);
00871         if (mount_list->me_type_malloced)
00872           free (mount_list->me_type);
00873         free (mount_list);
00874         mount_list = me;
00875       }
00876 
00877     errno = saved_errno;
00878     return NULL;
00879   }
00880 }