Blame sysdeps/unix/sysv/linux/shm-directory.c

Packit 6c4009
/* Determine directory for shm/sem files.  Linux version.
Packit 6c4009
   Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include "shm-directory.h"
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <mntent.h>
Packit 6c4009
#include <paths.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/statfs.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include "linux_fsinfo.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Mount point of the shared memory filesystem.  */
Packit 6c4009
static struct
Packit 6c4009
{
Packit 6c4009
  char *dir;
Packit 6c4009
  size_t dirlen;
Packit 6c4009
} mountpoint;
Packit 6c4009
Packit 6c4009
/* This is the default directory.  */
Packit 6c4009
static const char defaultdir[] = "/dev/shm/";
Packit 6c4009
Packit 6c4009
/* Protect the `mountpoint' variable above.  */
Packit 6c4009
__libc_once_define (static, once);
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Determine where the shmfs is mounted (if at all).  */
Packit 6c4009
static void
Packit 6c4009
where_is_shmfs (void)
Packit 6c4009
{
Packit 6c4009
  char buf[512];
Packit 6c4009
  struct statfs f;
Packit 6c4009
  struct mntent resmem;
Packit 6c4009
  struct mntent *mp;
Packit 6c4009
  FILE *fp;
Packit 6c4009
Packit 6c4009
  /* The canonical place is /dev/shm.  This is at least what the
Packit 6c4009
     documentation tells everybody to do.  */
Packit 6c4009
  if (__statfs (defaultdir, &f) == 0 && (f.f_type == SHMFS_SUPER_MAGIC
Packit 6c4009
                                         || f.f_type == RAMFS_MAGIC))
Packit 6c4009
    {
Packit 6c4009
      /* It is in the normal place.  */
Packit 6c4009
      mountpoint.dir = (char *) defaultdir;
Packit 6c4009
      mountpoint.dirlen = sizeof (defaultdir) - 1;
Packit 6c4009
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* OK, do it the hard way.  Look through the /proc/mounts file and if
Packit 6c4009
     this does not exist through /etc/fstab to find the mount point.  */
Packit 6c4009
  fp = __setmntent ("/proc/mounts", "r");
Packit 6c4009
  if (__glibc_unlikely (fp == NULL))
Packit 6c4009
    {
Packit 6c4009
      fp = __setmntent (_PATH_MNTTAB, "r");
Packit 6c4009
      if (__glibc_unlikely (fp == NULL))
Packit 6c4009
        /* There is nothing we can do.  Blind guesses are not helpful.  */
Packit 6c4009
        return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now read the entries.  */
Packit 6c4009
  while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
Packit 6c4009
    /* The original name is "shm" but this got changed in early Linux
Packit 6c4009
       2.4.x to "tmpfs".  */
Packit 6c4009
    if (strcmp (mp->mnt_type, "tmpfs") == 0
Packit 6c4009
        || strcmp (mp->mnt_type, "shm") == 0)
Packit 6c4009
      {
Packit 6c4009
        /* Found it.  There might be more than one place where the
Packit 6c4009
           filesystem is mounted but one is enough for us.  */
Packit 6c4009
        size_t namelen;
Packit 6c4009
Packit 6c4009
        /* First make sure this really is the correct entry.  At least
Packit 6c4009
           some versions of the kernel give wrong information because
Packit 6c4009
           of the implicit mount of the shmfs for SysV IPC.  */
Packit 6c4009
        if (__statfs (mp->mnt_dir, &f) != 0 || (f.f_type != SHMFS_SUPER_MAGIC
Packit 6c4009
                                                && f.f_type != RAMFS_MAGIC))
Packit 6c4009
          continue;
Packit 6c4009
Packit 6c4009
        namelen = strlen (mp->mnt_dir);
Packit 6c4009
Packit 6c4009
        if (namelen == 0)
Packit 6c4009
          /* Hum, maybe some crippled entry.  Keep on searching.  */
Packit 6c4009
          continue;
Packit 6c4009
Packit 6c4009
        mountpoint.dir = (char *) malloc (namelen + 2);
Packit 6c4009
        if (mountpoint.dir != NULL)
Packit 6c4009
          {
Packit 6c4009
            char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
Packit 6c4009
            if (cp[-1] != '/')
Packit 6c4009
              *cp++ = '/';
Packit 6c4009
            *cp = '\0';
Packit 6c4009
            mountpoint.dirlen = cp - mountpoint.dir;
Packit 6c4009
          }
Packit 6c4009
Packit 6c4009
        break;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Close the stream.  */
Packit 6c4009
  __endmntent (fp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
const char *
Packit 6c4009
__shm_directory (size_t *len)
Packit 6c4009
{
Packit 6c4009
  /* Determine where the shmfs is mounted.  */
Packit 6c4009
  __libc_once (once, where_is_shmfs);
Packit 6c4009
Packit 6c4009
  /* If we don't know the mount points there is nothing we can do.  Ever.  */
Packit 6c4009
  if (__glibc_unlikely (mountpoint.dir == NULL))
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOSYS);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *len = mountpoint.dirlen;
Packit 6c4009
  return mountpoint.dir;
Packit 6c4009
}
Packit 6c4009
#if IS_IN (libpthread)
Packit 6c4009
hidden_def (__shm_directory)
Packit 6c4009
Packit 6c4009
/* Make sure the table is freed if we want to free everything before
Packit 6c4009
   exiting.  */
Packit 6c4009
void
Packit 6c4009
__shm_directory_freeres (void)
Packit 6c4009
{
Packit 6c4009
  if (mountpoint.dir != defaultdir)
Packit 6c4009
    free (mountpoint.dir);
Packit 6c4009
}
Packit 6c4009
#endif