root/maint/gnulib/lib/mountlist.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. me_remote
  2. fstype_to_string
  3. fsp_to_string
  4. fstype_to_string
  5. dev_from_mount_options
  6. unescape_tab
  7. terminate_at_blank
  8. read_file_system_list
  9. free_mount_entry

   1 /* mountlist.c -- return a list of mounted file systems
   2 
   3    Copyright (C) 1991-1992, 1997-2021 Free Software Foundation, Inc.
   4 
   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.
   9 
  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.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 #include "mountlist.h"
  21 
  22 #include <limits.h>
  23 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 #include <stdint.h>
  27 
  28 #include "xalloc.h"
  29 
  30 #include <errno.h>
  31 
  32 #include <fcntl.h>
  33 
  34 #include <unistd.h>
  35 
  36 #if HAVE_SYS_PARAM_H
  37 # include <sys/param.h>
  38 #endif
  39 
  40 #if MAJOR_IN_MKDEV
  41 # include <sys/mkdev.h>
  42 #elif MAJOR_IN_SYSMACROS
  43 # include <sys/sysmacros.h>
  44 #endif
  45 
  46 #if defined MOUNTED_GETFSSTAT   /* OSF/1, also (obsolete) Apple Darwin 1.3 */
  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 */
  64 
  65 #ifdef MOUNTED_GETMNTENT1       /* glibc, HP-UX, IRIX, Cygwin, Android,
  66                                    also (obsolete) 4.3BSD, SunOS */
  67 # include <mntent.h>
  68 # include <sys/types.h>
  69 # if defined __ANDROID__        /* Android */
  70    /* Bionic versions from between 2014-01-09 and 2015-01-08 define MOUNTED to
  71       an incorrect value; older Bionic versions don't define it at all.  */
  72 #  undef MOUNTED
  73 #  define MOUNTED "/proc/mounts"
  74 # elif !defined MOUNTED
  75 #  if defined _PATH_MOUNTED     /* GNU libc  */
  76 #   define MOUNTED _PATH_MOUNTED
  77 #  endif
  78 #  if defined MNT_MNTTAB        /* HP-UX.  */
  79 #   define MOUNTED MNT_MNTTAB
  80 #  endif
  81 # endif
  82 #endif
  83 
  84 #ifdef MOUNTED_GETMNTINFO       /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
  85 # include <sys/mount.h>
  86 #endif
  87 
  88 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD, Minix */
  89 # include <sys/statvfs.h>
  90 #endif
  91 
  92 #ifdef MOUNTED_FS_STAT_DEV      /* Haiku, also (obsolete) BeOS */
  93 # include <fs_info.h>
  94 # include <dirent.h>
  95 #endif
  96 
  97 #ifdef MOUNTED_FREAD_FSTYP      /* (obsolete) SVR3 */
  98 # include <mnttab.h>
  99 # include <sys/fstyp.h>
 100 # include <sys/statfs.h>
 101 #endif
 102 
 103 #ifdef MOUNTED_GETEXTMNTENT     /* Solaris >= 8 */
 104 # include <sys/mnttab.h>
 105 #endif
 106 
 107 #ifdef MOUNTED_GETMNTENT2       /* Solaris < 8, also (obsolete) SVR4 */
 108 # include <sys/mnttab.h>
 109 #endif
 110 
 111 #ifdef MOUNTED_VMOUNT           /* AIX */
 112 # include <fshelp.h>
 113 # include <sys/vfs.h>
 114 #endif
 115 
 116 #ifdef MOUNTED_INTERIX_STATVFS  /* Interix */
 117 # include <sys/statvfs.h>
 118 # include <dirent.h>
 119 #endif
 120 
 121 #if HAVE_SYS_MNTENT_H
 122 /* This is to get MNTOPT_IGNORE on e.g. SVR4.  */
 123 # include <sys/mntent.h>
 124 #endif
 125 
 126 #ifdef MOUNTED_GETMNTENT1
 127 # if !HAVE_SETMNTENT            /* Android <= 4.4 */
 128 #  define setmntent(fp,mode) fopen (fp, mode "e")
 129 # endif
 130 # if !HAVE_ENDMNTENT            /* Android <= 4.4 */
 131 #  define endmntent(fp) fclose (fp)
 132 # endif
 133 #endif
 134 
 135 #ifndef HAVE_HASMNTOPT
 136 # define hasmntopt(mnt, opt) ((char *) 0)
 137 #endif
 138 
 139 #undef MNT_IGNORE
 140 #ifdef MNTOPT_IGNORE
 141 # if defined __sun && defined __SVR4
 142 /* Solaris defines hasmntopt(struct mnttab *, char *)
 143    while it is otherwise hasmntopt(struct mnttab *, const char *).  */
 144 #  define MNT_IGNORE(M) hasmntopt (M, (char *) MNTOPT_IGNORE)
 145 # else
 146 #  define MNT_IGNORE(M) hasmntopt (M, MNTOPT_IGNORE)
 147 # endif
 148 #else
 149 # define MNT_IGNORE(M) 0
 150 #endif
 151 
 152 /* Each of the FILE streams in this file is only used in a single thread.  */
 153 #include "unlocked-io.h"
 154 
 155 /* The results of opendir() in this file are not used with dirfd and fchdir,
 156    therefore save some unnecessary work in fchdir.c.  */
 157 #ifdef GNULIB_defined_opendir
 158 # undef opendir
 159 #endif
 160 #ifdef GNULIB_defined_closedir
 161 # undef closedir
 162 #endif
 163 
 164 #define ME_DUMMY_0(Fs_name, Fs_type)            \
 165   (strcmp (Fs_type, "autofs") == 0              \
 166    || strcmp (Fs_type, "proc") == 0             \
 167    || strcmp (Fs_type, "subfs") == 0            \
 168    /* for Linux 2.6/3.x */                      \
 169    || strcmp (Fs_type, "debugfs") == 0          \
 170    || strcmp (Fs_type, "devpts") == 0           \
 171    || strcmp (Fs_type, "fusectl") == 0          \
 172    || strcmp (Fs_type, "fuse.portal") == 0      \
 173    || strcmp (Fs_type, "mqueue") == 0           \
 174    || strcmp (Fs_type, "rpc_pipefs") == 0       \
 175    || strcmp (Fs_type, "sysfs") == 0            \
 176    /* FreeBSD, Linux 2.4 */                     \
 177    || strcmp (Fs_type, "devfs") == 0            \
 178    /* for NetBSD 3.0 */                         \
 179    || strcmp (Fs_type, "kernfs") == 0           \
 180    /* for Irix 6.5 */                           \
 181    || strcmp (Fs_type, "ignore") == 0)
 182 
 183 /* Historically, we have marked as "dummy" any file system of type "none",
 184    but now that programs like du need to know about bind-mounted directories,
 185    we grant an exception to any with "bind" in its list of mount options.
 186    I.e., those are *not* dummy entries.  */
 187 #ifdef MOUNTED_GETMNTENT1
 188 # define ME_DUMMY(Fs_name, Fs_type, Bind)       \
 189   (ME_DUMMY_0 (Fs_name, Fs_type)                \
 190    || (strcmp (Fs_type, "none") == 0 && !Bind))
 191 #else
 192 # define ME_DUMMY(Fs_name, Fs_type)             \
 193   (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
 194 #endif
 195 
 196 #ifdef __CYGWIN__
 197 # include <windows.h>
 198 /* Don't assume that UNICODE is not defined.  */
 199 # undef GetDriveType
 200 # define GetDriveType GetDriveTypeA
 201 # define ME_REMOTE me_remote
 202 /* All cygwin mount points include ':' or start with '//'; so it
 203    requires a native Windows call to determine remote disks.  */
 204 static bool
 205 me_remote (char const *fs_name, _GL_UNUSED char const *fs_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207   if (fs_name[0] && fs_name[1] == ':')
 208     {
 209       char drive[4];
 210       sprintf (drive, "%c:\\", fs_name[0]);
 211       switch (GetDriveType (drive))
 212         {
 213         case DRIVE_REMOVABLE:
 214         case DRIVE_FIXED:
 215         case DRIVE_CDROM:
 216         case DRIVE_RAMDISK:
 217           return false;
 218         }
 219     }
 220   return true;
 221 }
 222 #endif
 223 
 224 #ifndef ME_REMOTE
 225 /* A file system is "remote" if its Fs_name contains a ':'
 226    or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
 227    or if it is of any other of the listed types
 228    or Fs_name is equal to "-hosts" (used by autofs to mount remote fs).
 229    "VM" file systems like prl_fs or vboxsf are not considered remote here. */
 230 # define ME_REMOTE(Fs_name, Fs_type)            \
 231     (strchr (Fs_name, ':') != NULL              \
 232      || ((Fs_name)[0] == '/'                    \
 233          && (Fs_name)[1] == '/'                 \
 234          && (strcmp (Fs_type, "smbfs") == 0     \
 235              || strcmp (Fs_type, "smb3") == 0   \
 236              || strcmp (Fs_type, "cifs") == 0)) \
 237      || strcmp (Fs_type, "acfs") == 0           \
 238      || strcmp (Fs_type, "afs") == 0            \
 239      || strcmp (Fs_type, "coda") == 0           \
 240      || strcmp (Fs_type, "auristorfs") == 0     \
 241      || strcmp (Fs_type, "fhgfs") == 0          \
 242      || strcmp (Fs_type, "gpfs") == 0           \
 243      || strcmp (Fs_type, "ibrix") == 0          \
 244      || strcmp (Fs_type, "ocfs2") == 0          \
 245      || strcmp (Fs_type, "vxfs") == 0           \
 246      || strcmp ("-hosts", Fs_name) == 0)
 247 #endif
 248 
 249 #if MOUNTED_GETMNTINFO          /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
 250 
 251 # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME
 252 static char *
 253 fstype_to_string (short int t)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255   switch (t)
 256     {
 257 #  ifdef MOUNT_PC
 258     case MOUNT_PC:
 259       return "pc";
 260 #  endif
 261 #  ifdef MOUNT_MFS
 262     case MOUNT_MFS:
 263       return "mfs";
 264 #  endif
 265 #  ifdef MOUNT_LO
 266     case MOUNT_LO:
 267       return "lo";
 268 #  endif
 269 #  ifdef MOUNT_TFS
 270     case MOUNT_TFS:
 271       return "tfs";
 272 #  endif
 273 #  ifdef MOUNT_TMP
 274     case MOUNT_TMP:
 275       return "tmp";
 276 #  endif
 277 #  ifdef MOUNT_UFS
 278    case MOUNT_UFS:
 279      return "ufs" ;
 280 #  endif
 281 #  ifdef MOUNT_NFS
 282    case MOUNT_NFS:
 283      return "nfs" ;
 284 #  endif
 285 #  ifdef MOUNT_MSDOS
 286    case MOUNT_MSDOS:
 287      return "msdos" ;
 288 #  endif
 289 #  ifdef MOUNT_LFS
 290    case MOUNT_LFS:
 291      return "lfs" ;
 292 #  endif
 293 #  ifdef MOUNT_LOFS
 294    case MOUNT_LOFS:
 295      return "lofs" ;
 296 #  endif
 297 #  ifdef MOUNT_FDESC
 298    case MOUNT_FDESC:
 299      return "fdesc" ;
 300 #  endif
 301 #  ifdef MOUNT_PORTAL
 302    case MOUNT_PORTAL:
 303      return "portal" ;
 304 #  endif
 305 #  ifdef MOUNT_NULL
 306    case MOUNT_NULL:
 307      return "null" ;
 308 #  endif
 309 #  ifdef MOUNT_UMAP
 310    case MOUNT_UMAP:
 311      return "umap" ;
 312 #  endif
 313 #  ifdef MOUNT_KERNFS
 314    case MOUNT_KERNFS:
 315      return "kernfs" ;
 316 #  endif
 317 #  ifdef MOUNT_PROCFS
 318    case MOUNT_PROCFS:
 319      return "procfs" ;
 320 #  endif
 321 #  ifdef MOUNT_AFS
 322    case MOUNT_AFS:
 323      return "afs" ;
 324 #  endif
 325 #  ifdef MOUNT_CD9660
 326    case MOUNT_CD9660:
 327      return "cd9660" ;
 328 #  endif
 329 #  ifdef MOUNT_UNION
 330    case MOUNT_UNION:
 331      return "union" ;
 332 #  endif
 333 #  ifdef MOUNT_DEVFS
 334    case MOUNT_DEVFS:
 335      return "devfs" ;
 336 #  endif
 337 #  ifdef MOUNT_EXT2FS
 338    case MOUNT_EXT2FS:
 339      return "ext2fs" ;
 340 #  endif
 341     default:
 342       return "?";
 343     }
 344 }
 345 # endif
 346 
 347 static char *
 348 fsp_to_string (const struct statfs *fsp)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
 351   return (char *) (fsp->f_fstypename);
 352 # else
 353   return fstype_to_string (fsp->f_type);
 354 # endif
 355 }
 356 
 357 #endif /* MOUNTED_GETMNTINFO */
 358 
 359 #ifdef MOUNTED_VMOUNT           /* AIX */
 360 static char *
 361 fstype_to_string (int t)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363   struct vfs_ent *e;
 364 
 365   e = getvfsbytype (t);
 366   if (!e || !e->vfsent_name)
 367     return "none";
 368   else
 369     return e->vfsent_name;
 370 }
 371 #endif /* MOUNTED_VMOUNT */
 372 
 373 
 374 #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
 375 
 376 /* Return the device number from MOUNT_OPTIONS, if possible.
 377    Otherwise return (dev_t) -1.  */
 378 static dev_t
 379 dev_from_mount_options (char const *mount_options)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381   /* GNU/Linux allows file system implementations to define their own
 382      meaning for "dev=" mount options, so don't trust the meaning
 383      here.  */
 384 # ifndef __linux__
 385 
 386   static char const dev_pattern[] = ",dev=";
 387   char const *devopt = strstr (mount_options, dev_pattern);
 388 
 389   if (devopt)
 390     {
 391       char const *optval = devopt + sizeof dev_pattern - 1;
 392       char *optvalend;
 393       unsigned long int dev;
 394       errno = 0;
 395       dev = strtoul (optval, &optvalend, 16);
 396       if (optval != optvalend
 397           && (*optvalend == '\0' || *optvalend == ',')
 398           && ! (dev == ULONG_MAX && errno == ERANGE)
 399           && dev == (dev_t) dev)
 400         return dev;
 401     }
 402 
 403 # endif
 404   (void) mount_options;
 405   return -1;
 406 }
 407 
 408 #endif
 409 
 410 #if defined MOUNTED_GETMNTENT1 && (defined __linux__ || defined __ANDROID__) /* GNU/Linux, Android */
 411 
 412 /* Unescape the paths in mount tables.
 413    STR is updated in place.  */
 414 
 415 static void
 416 unescape_tab (char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418   size_t i, j = 0;
 419   size_t len = strlen (str) + 1;
 420   for (i = 0; i < len; i++)
 421     {
 422       if (str[i] == '\\' && (i + 4 < len)
 423           && str[i + 1] >= '0' && str[i + 1] <= '3'
 424           && str[i + 2] >= '0' && str[i + 2] <= '7'
 425           && str[i + 3] >= '0' && str[i + 3] <= '7')
 426         {
 427           str[j++] = (str[i + 1] - '0') * 64 +
 428                      (str[i + 2] - '0') * 8 +
 429                      (str[i + 3] - '0');
 430           i += 3;
 431         }
 432       else
 433         str[j++] = str[i];
 434     }
 435 }
 436 
 437 /* Find the next space in STR, terminate the string there in place,
 438    and return that position.  Otherwise return NULL.  */
 439 
 440 static char *
 441 terminate_at_blank (char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443   char *s = strchr (str, ' ');
 444   if (s)
 445     *s = '\0';
 446   return s;
 447 }
 448 #endif
 449 
 450 /* Return a list of the currently mounted file systems, or NULL on error.
 451    Add each entry to the tail of the list so that they stay in order.
 452    If NEED_FS_TYPE is true, ensure that the file system type fields in
 453    the returned list are valid.  Otherwise, they might not be.  */
 454 
 455 struct mount_entry *
 456 read_file_system_list (bool need_fs_type)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458   struct mount_entry *mount_list;
 459   struct mount_entry *me;
 460   struct mount_entry **mtail = &mount_list;
 461   (void) need_fs_type;
 462 
 463 #ifdef MOUNTED_GETMNTENT1       /* glibc, HP-UX, IRIX, Cygwin, Android,
 464                                    also (obsolete) 4.3BSD, SunOS */
 465   {
 466     FILE *fp;
 467 
 468 # if defined __linux__ || defined __ANDROID__
 469     /* Try parsing mountinfo first, as that make device IDs available.
 470        Note we could use libmount routines to simplify this parsing a little
 471        (and that code is in previous versions of this function), however
 472        libmount depends on libselinux which pulls in many dependencies.  */
 473     char const *mountinfo = "/proc/self/mountinfo";
 474     fp = fopen (mountinfo, "re");
 475     if (fp != NULL)
 476       {
 477         char *line = NULL;
 478         size_t buf_size = 0;
 479 
 480         while (getline (&line, &buf_size, fp) != -1)
 481           {
 482             unsigned int devmaj, devmin;
 483             int rc, mntroot_s;
 484 
 485             rc = sscanf(line, "%*u "        /* id - discarded  */
 486                               "%*u "        /* parent - discarded  */
 487                               "%u:%u "      /* dev major:minor  */
 488                               "%n",         /* mountroot (start)  */
 489                               &devmaj, &devmin,
 490                               &mntroot_s);
 491 
 492             if (rc != 2 && rc != 3)  /* 3 if %n included in count.  */
 493               continue;
 494 
 495             /* find end of MNTROOT.  */
 496             char *mntroot = line + mntroot_s;
 497             char *blank = terminate_at_blank (mntroot);
 498             if (! blank)
 499               continue;
 500 
 501             /* find end of TARGET.  */
 502             char *target = blank + 1;
 503             blank = terminate_at_blank (target);
 504             if (! blank)
 505               continue;
 506 
 507             /* skip optional fields, terminated by " - "  */
 508             char *dash = strstr (blank + 1, " - ");
 509             if (! dash)
 510               continue;
 511 
 512             /* advance past the " - " separator.  */
 513             char *fstype = dash + 3;
 514             blank = terminate_at_blank (fstype);
 515             if (! blank)
 516               continue;
 517 
 518             /* find end of SOURCE.  */
 519             char *source = blank + 1;
 520             if (! terminate_at_blank (source))
 521               continue;
 522 
 523             /* manipulate the sub-strings in place.  */
 524             unescape_tab (source);
 525             unescape_tab (target);
 526             unescape_tab (mntroot);
 527             unescape_tab (fstype);
 528 
 529             me = xmalloc (sizeof *me);
 530 
 531             me->me_devname = xstrdup (source);
 532             me->me_mountdir = xstrdup (target);
 533             me->me_mntroot = xstrdup (mntroot);
 534             me->me_type = xstrdup (fstype);
 535             me->me_type_malloced = 1;
 536             me->me_dev = makedev (devmaj, devmin);
 537             /* we pass "false" for the "Bind" option as that's only
 538                significant when the Fs_type is "none" which will not be
 539                the case when parsing "/proc/self/mountinfo", and only
 540                applies for static /etc/mtab files.  */
 541             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false);
 542             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 543 
 544             /* Add to the linked list. */
 545             *mtail = me;
 546             mtail = &me->me_next;
 547           }
 548 
 549         free (line);
 550 
 551         if (ferror (fp))
 552           {
 553             int saved_errno = errno;
 554             fclose (fp);
 555             errno = saved_errno;
 556             goto free_then_fail;
 557           }
 558 
 559         if (fclose (fp) == EOF)
 560           goto free_then_fail;
 561       }
 562     else /* fallback to /proc/self/mounts (/etc/mtab).  */
 563 # endif /* __linux __ || __ANDROID__ */
 564       {
 565         struct mntent *mnt;
 566         char const *table = MOUNTED;
 567 
 568         fp = setmntent (table, "r");
 569         if (fp == NULL)
 570           return NULL;
 571 
 572         while ((mnt = getmntent (fp)))
 573           {
 574             bool bind = hasmntopt (mnt, "bind");
 575 
 576             me = xmalloc (sizeof *me);
 577             me->me_devname = xstrdup (mnt->mnt_fsname);
 578             me->me_mountdir = xstrdup (mnt->mnt_dir);
 579             me->me_mntroot = NULL;
 580             me->me_type = xstrdup (mnt->mnt_type);
 581             me->me_type_malloced = 1;
 582             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, bind);
 583             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 584             me->me_dev = dev_from_mount_options (mnt->mnt_opts);
 585 
 586             /* Add to the linked list. */
 587             *mtail = me;
 588             mtail = &me->me_next;
 589           }
 590 
 591         if (endmntent (fp) == 0)
 592           goto free_then_fail;
 593       }
 594   }
 595 #endif /* MOUNTED_GETMNTENT1. */
 596 
 597 #ifdef MOUNTED_GETMNTINFO       /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */
 598   {
 599     struct statfs *fsp;
 600     int entries;
 601 
 602     entries = getmntinfo (&fsp, MNT_NOWAIT);
 603     if (entries < 0)
 604       return NULL;
 605     for (; entries-- > 0; fsp++)
 606       {
 607         char *fs_type = fsp_to_string (fsp);
 608 
 609         me = xmalloc (sizeof *me);
 610         me->me_devname = xstrdup (fsp->f_mntfromname);
 611         me->me_mountdir = xstrdup (fsp->f_mntonname);
 612         me->me_mntroot = NULL;
 613         me->me_type = fs_type;
 614         me->me_type_malloced = 0;
 615         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
 616         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 617         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
 618 
 619         /* Add to the linked list. */
 620         *mtail = me;
 621         mtail = &me->me_next;
 622       }
 623   }
 624 #endif /* MOUNTED_GETMNTINFO */
 625 
 626 #ifdef MOUNTED_GETMNTINFO2      /* NetBSD, Minix */
 627   {
 628     struct statvfs *fsp;
 629     int entries;
 630 
 631     entries = getmntinfo (&fsp, MNT_NOWAIT);
 632     if (entries < 0)
 633       return NULL;
 634     for (; entries-- > 0; fsp++)
 635       {
 636         me = xmalloc (sizeof *me);
 637         me->me_devname = xstrdup (fsp->f_mntfromname);
 638         me->me_mountdir = xstrdup (fsp->f_mntonname);
 639         me->me_mntroot = NULL;
 640         me->me_type = xstrdup (fsp->f_fstypename);
 641         me->me_type_malloced = 1;
 642         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
 643         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 644         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
 645 
 646         /* Add to the linked list. */
 647         *mtail = me;
 648         mtail = &me->me_next;
 649       }
 650   }
 651 #endif /* MOUNTED_GETMNTINFO2 */
 652 
 653 #if defined MOUNTED_FS_STAT_DEV /* Haiku, also (obsolete) BeOS */
 654   {
 655     /* The next_dev() and fs_stat_dev() system calls give the list of
 656        all file systems, including the information returned by statvfs()
 657        (fs type, total blocks, free blocks etc.), but without the mount
 658        point. But on BeOS all file systems except / are mounted in the
 659        rootfs, directly under /.
 660        The directory name of the mount point is often, but not always,
 661        identical to the volume name of the device.
 662        We therefore get the list of subdirectories of /, and the list
 663        of all file systems, and match the two lists.  */
 664 
 665     DIR *dirp;
 666     struct rootdir_entry
 667       {
 668         char *name;
 669         dev_t dev;
 670         ino_t ino;
 671         struct rootdir_entry *next;
 672       };
 673     struct rootdir_entry *rootdir_list;
 674     struct rootdir_entry **rootdir_tail;
 675     int32 pos;
 676     dev_t dev;
 677     fs_info fi;
 678 
 679     /* All volumes are mounted in the rootfs, directly under /. */
 680     rootdir_list = NULL;
 681     rootdir_tail = &rootdir_list;
 682     dirp = opendir ("/");
 683     if (dirp)
 684       {
 685         struct dirent *d;
 686 
 687         while ((d = readdir (dirp)) != NULL)
 688           {
 689             char *name;
 690             struct stat statbuf;
 691 
 692             if (strcmp (d->d_name, "..") == 0)
 693               continue;
 694 
 695             if (strcmp (d->d_name, ".") == 0)
 696               name = xstrdup ("/");
 697             else
 698               {
 699                 name = xmalloc (1 + strlen (d->d_name) + 1);
 700                 name[0] = '/';
 701                 strcpy (name + 1, d->d_name);
 702               }
 703 
 704             if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode))
 705               {
 706                 struct rootdir_entry *re = xmalloc (sizeof *re);
 707                 re->name = name;
 708                 re->dev = statbuf.st_dev;
 709                 re->ino = statbuf.st_ino;
 710 
 711                 /* Add to the linked list.  */
 712                 *rootdir_tail = re;
 713                 rootdir_tail = &re->next;
 714               }
 715             else
 716               free (name);
 717           }
 718         closedir (dirp);
 719       }
 720     *rootdir_tail = NULL;
 721 
 722     for (pos = 0; (dev = next_dev (&pos)) >= 0; )
 723       if (fs_stat_dev (dev, &fi) >= 0)
 724         {
 725           /* Note: fi.dev == dev. */
 726           struct rootdir_entry *re;
 727 
 728           for (re = rootdir_list; re; re = re->next)
 729             if (re->dev == fi.dev && re->ino == fi.root)
 730               break;
 731 
 732           me = xmalloc (sizeof *me);
 733           me->me_devname = xstrdup (fi.device_name[0] != '\0'
 734                                     ? fi.device_name : fi.fsh_name);
 735           me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name);
 736           me->me_mntroot = NULL;
 737           me->me_type = xstrdup (fi.fsh_name);
 738           me->me_type_malloced = 1;
 739           me->me_dev = fi.dev;
 740           me->me_dummy = 0;
 741           me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0;
 742 
 743           /* Add to the linked list. */
 744           *mtail = me;
 745           mtail = &me->me_next;
 746         }
 747     *mtail = NULL;
 748 
 749     while (rootdir_list != NULL)
 750       {
 751         struct rootdir_entry *re = rootdir_list;
 752         rootdir_list = re->next;
 753         free (re->name);
 754         free (re);
 755       }
 756   }
 757 #endif /* MOUNTED_FS_STAT_DEV */
 758 
 759 #if defined MOUNTED_GETFSSTAT   /* OSF/1, also (obsolete) Apple Darwin 1.3 */
 760   {
 761     int numsys, counter;
 762     size_t bufsize;
 763     struct statfs *stats;
 764 
 765     numsys = getfsstat (NULL, 0L, MNT_NOWAIT);
 766     if (numsys < 0)
 767       return NULL;
 768     if (SIZE_MAX / sizeof *stats <= numsys)
 769       xalloc_die ();
 770 
 771     bufsize = (1 + numsys) * sizeof *stats;
 772     stats = xmalloc (bufsize);
 773     numsys = getfsstat (stats, bufsize, MNT_NOWAIT);
 774 
 775     if (numsys < 0)
 776       {
 777         free (stats);
 778         return NULL;
 779       }
 780 
 781     for (counter = 0; counter < numsys; counter++)
 782       {
 783         me = xmalloc (sizeof *me);
 784         me->me_devname = xstrdup (stats[counter].f_mntfromname);
 785         me->me_mountdir = xstrdup (stats[counter].f_mntonname);
 786         me->me_mntroot = NULL;
 787         me->me_type = xstrdup (FS_TYPE (stats[counter]));
 788         me->me_type_malloced = 1;
 789         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
 790         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 791         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
 792 
 793         /* Add to the linked list. */
 794         *mtail = me;
 795         mtail = &me->me_next;
 796       }
 797 
 798     free (stats);
 799   }
 800 #endif /* MOUNTED_GETFSSTAT */
 801 
 802 #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */
 803   {
 804     struct mnttab mnt;
 805     char *table = "/etc/mnttab";
 806     FILE *fp;
 807 
 808     fp = fopen (table, "re");
 809     if (fp == NULL)
 810       return NULL;
 811 
 812     while (fread (&mnt, sizeof mnt, 1, fp) > 0)
 813       {
 814         me = xmalloc (sizeof *me);
 815         me->me_devname = xstrdup (mnt.mt_dev);
 816         me->me_mountdir = xstrdup (mnt.mt_filsys);
 817         me->me_mntroot = NULL;
 818         me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
 819         me->me_type = "";
 820         me->me_type_malloced = 0;
 821         if (need_fs_type)
 822           {
 823             struct statfs fsd;
 824             char typebuf[FSTYPSZ];
 825 
 826             if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
 827                 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
 828               {
 829                 me->me_type = xstrdup (typebuf);
 830                 me->me_type_malloced = 1;
 831               }
 832           }
 833         me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
 834         me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 835 
 836         /* Add to the linked list. */
 837         *mtail = me;
 838         mtail = &me->me_next;
 839       }
 840 
 841     if (ferror (fp))
 842       {
 843         /* The last fread() call must have failed.  */
 844         int saved_errno = errno;
 845         fclose (fp);
 846         errno = saved_errno;
 847         goto free_then_fail;
 848       }
 849 
 850     if (fclose (fp) == EOF)
 851       goto free_then_fail;
 852   }
 853 #endif /* MOUNTED_FREAD_FSTYP.  */
 854 
 855 #ifdef MOUNTED_GETEXTMNTENT     /* Solaris >= 8 */
 856   {
 857     struct extmnttab mnt;
 858     const char *table = MNTTAB;
 859     FILE *fp;
 860     int ret;
 861 
 862     /* No locking is needed, because the contents of /etc/mnttab is generated
 863        by the kernel.  */
 864 
 865     errno = 0;
 866     fp = fopen (table, "re");
 867     if (fp == NULL)
 868       ret = errno;
 869     else
 870       {
 871         while ((ret = getextmntent (fp, &mnt, 1)) == 0)
 872           {
 873             me = xmalloc (sizeof *me);
 874             me->me_devname = xstrdup (mnt.mnt_special);
 875             me->me_mountdir = xstrdup (mnt.mnt_mountp);
 876             me->me_mntroot = NULL;
 877             me->me_type = xstrdup (mnt.mnt_fstype);
 878             me->me_type_malloced = 1;
 879             me->me_dummy = MNT_IGNORE (&mnt) != 0;
 880             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 881             me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor);
 882 
 883             /* Add to the linked list. */
 884             *mtail = me;
 885             mtail = &me->me_next;
 886           }
 887 
 888         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
 889         /* Here ret = -1 means success, ret >= 0 means failure.  */
 890       }
 891 
 892     if (0 <= ret)
 893       {
 894         errno = ret;
 895         goto free_then_fail;
 896       }
 897   }
 898 #endif /* MOUNTED_GETEXTMNTENT */
 899 
 900 #ifdef MOUNTED_GETMNTENT2       /* Solaris < 8, also (obsolete) SVR4 */
 901   {
 902     struct mnttab mnt;
 903     const char *table = MNTTAB;
 904     FILE *fp;
 905     int ret;
 906     int lockfd = -1;
 907 
 908 # if defined F_RDLCK && defined F_SETLKW
 909     /* MNTTAB_LOCK is a macro name of our own invention; it's not present in
 910        e.g. Solaris 2.6.  If the SVR4 folks ever define a macro
 911        for this file name, we should use their macro name instead.
 912        (Why not just lock MNTTAB directly?  We don't know.)  */
 913 #  ifndef MNTTAB_LOCK
 914 #   define MNTTAB_LOCK "/etc/.mnttab.lock"
 915 #  endif
 916     lockfd = open (MNTTAB_LOCK, O_RDONLY | O_CLOEXEC);
 917     if (0 <= lockfd)
 918       {
 919         struct flock flock;
 920         flock.l_type = F_RDLCK;
 921         flock.l_whence = SEEK_SET;
 922         flock.l_start = 0;
 923         flock.l_len = 0;
 924         while (fcntl (lockfd, F_SETLKW, &flock) == -1)
 925           if (errno != EINTR)
 926             {
 927               int saved_errno = errno;
 928               close (lockfd);
 929               errno = saved_errno;
 930               return NULL;
 931             }
 932       }
 933     else if (errno != ENOENT)
 934       return NULL;
 935 # endif
 936 
 937     errno = 0;
 938     fp = fopen (table, "re");
 939     if (fp == NULL)
 940       ret = errno;
 941     else
 942       {
 943         while ((ret = getmntent (fp, &mnt)) == 0)
 944           {
 945             me = xmalloc (sizeof *me);
 946             me->me_devname = xstrdup (mnt.mnt_special);
 947             me->me_mountdir = xstrdup (mnt.mnt_mountp);
 948             me->me_mntroot = NULL;
 949             me->me_type = xstrdup (mnt.mnt_fstype);
 950             me->me_type_malloced = 1;
 951             me->me_dummy = MNT_IGNORE (&mnt) != 0;
 952             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
 953             me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
 954 
 955             /* Add to the linked list. */
 956             *mtail = me;
 957             mtail = &me->me_next;
 958           }
 959 
 960         ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1;
 961         /* Here ret = -1 means success, ret >= 0 means failure.  */
 962       }
 963 
 964     if (0 <= lockfd && close (lockfd) != 0)
 965       ret = errno;
 966 
 967     if (0 <= ret)
 968       {
 969         errno = ret;
 970         goto free_then_fail;
 971       }
 972   }
 973 #endif /* MOUNTED_GETMNTENT2.  */
 974 
 975 #ifdef MOUNTED_VMOUNT           /* AIX */
 976   {
 977     int bufsize;
 978     void *entries;
 979     char *thisent;
 980     struct vmount *vmp;
 981     int n_entries;
 982     int i;
 983 
 984     /* Ask how many bytes to allocate for the mounted file system info.  */
 985     entries = &bufsize;
 986     if (mntctl (MCTL_QUERY, sizeof bufsize, entries) != 0)
 987       return NULL;
 988     entries = xmalloc (bufsize);
 989 
 990     /* Get the list of mounted file systems.  */
 991     n_entries = mntctl (MCTL_QUERY, bufsize, entries);
 992     if (n_entries < 0)
 993       {
 994         free (entries);
 995         return NULL;
 996       }
 997 
 998     for (i = 0, thisent = entries;
 999          i < n_entries;
1000          i++, thisent += vmp->vmt_length)
1001       {
1002         char *options, *ignore;
1003 
1004         vmp = (struct vmount *) thisent;
1005         me = xmalloc (sizeof *me);
1006         if (vmp->vmt_flags & MNT_REMOTE)
1007           {
1008             char *host, *dir;
1009 
1010             me->me_remote = 1;
1011             /* Prepend the remote dirname.  */
1012             host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
1013             dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
1014             me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2);
1015             strcpy (me->me_devname, host);
1016             strcat (me->me_devname, ":");
1017             strcat (me->me_devname, dir);
1018           }
1019         else
1020           {
1021             me->me_remote = 0;
1022             me->me_devname = xstrdup (thisent +
1023                                       vmp->vmt_data[VMT_OBJECT].vmt_off);
1024           }
1025         me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
1026         me->me_mntroot = NULL;
1027         me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype));
1028         me->me_type_malloced = 1;
1029         options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off;
1030         ignore = strstr (options, "ignore");
1031         me->me_dummy = (ignore
1032                         && (ignore == options || ignore[-1] == ',')
1033                         && (ignore[sizeof "ignore" - 1] == ','
1034                             || ignore[sizeof "ignore" - 1] == '\0'));
1035         me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want.  */
1036 
1037         /* Add to the linked list. */
1038         *mtail = me;
1039         mtail = &me->me_next;
1040       }
1041     free (entries);
1042   }
1043 #endif /* MOUNTED_VMOUNT. */
1044 
1045 #ifdef MOUNTED_INTERIX_STATVFS  /* Interix */
1046   {
1047     DIR *dirp = opendir ("/dev/fs");
1048     char node[9 + NAME_MAX];
1049 
1050     if (!dirp)
1051       goto free_then_fail;
1052 
1053     while (1)
1054       {
1055         struct statvfs dev;
1056         struct dirent entry;
1057         struct dirent *result;
1058 
1059         /* FIXME: readdir_r is planned to be withdrawn from POSIX and
1060            marked obsolescent in glibc.  Use readdir instead.  */
1061         if (readdir_r (dirp, &entry, &result) || result == NULL)
1062           break;
1063 
1064         strcpy (node, "/dev/fs/");
1065         strcat (node, entry.d_name);
1066 
1067         if (statvfs (node, &dev) == 0)
1068           {
1069             me = xmalloc (sizeof *me);
1070             me->me_devname = xstrdup (dev.f_mntfromname);
1071             me->me_mountdir = xstrdup (dev.f_mntonname);
1072             me->me_mntroot = NULL;
1073             me->me_type = xstrdup (dev.f_fstypename);
1074             me->me_type_malloced = 1;
1075             me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
1076             me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
1077             me->me_dev = (dev_t) -1;        /* Magic; means not known yet. */
1078 
1079             /* Add to the linked list. */
1080             *mtail = me;
1081             mtail = &me->me_next;
1082           }
1083       }
1084     closedir (dirp);
1085   }
1086 #endif /* MOUNTED_INTERIX_STATVFS */
1087 
1088   *mtail = NULL;
1089   return mount_list;
1090 
1091 
1092  free_then_fail: _GL_UNUSED_LABEL;
1093   {
1094     int saved_errno = errno;
1095     *mtail = NULL;
1096 
1097     while (mount_list)
1098       {
1099         me = mount_list->me_next;
1100         free_mount_entry (mount_list);
1101         mount_list = me;
1102       }
1103 
1104     errno = saved_errno;
1105     return NULL;
1106   }
1107 }
1108 
1109 /* Free a mount entry as returned from read_file_system_list ().  */
1110 
1111 void
1112 free_mount_entry (struct mount_entry *me)
     /* [previous][next][first][last][top][bottom][index][help] */
1113 {
1114   free (me->me_devname);
1115   free (me->me_mountdir);
1116   free (me->me_mntroot);
1117   if (me->me_type_malloced)
1118     free (me->me_type);
1119   free (me);
1120 }

/* [previous][next][first][last][top][bottom][index][help] */