Back to index

glibc  2.9
Functions | Variables
shm_open.c File Reference
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/statfs.h>
#include <bits/libc-lock.h>
#include "linux_fsinfo.h"
#include <kernel-features.h>

Go to the source code of this file.

Functions

 __libc_once_define (static, once)
static void where_is_shmfs (void)
int shm_open (const char *name, int oflag, mode_t mode)
int shm_unlink (const char *name)
 libc_freeres_fn (freeit)

Variables

struct {
char * dir
size_t dirlen
mountpoint
static const char defaultdir [] = "/dev/shm/"

Function Documentation

__libc_once_define ( static  ,
once   
)
libc_freeres_fn ( freeit  )

Definition at line 267 of file shm_open.c.

{
  if (mountpoint.dir != defaultdir)
    free (mountpoint.dir);
}
int shm_open ( const char *  name,
int  oflag,
mode_t  mode 
)

Definition at line 136 of file shm_open.c.

{
  size_t namelen;
  char *fname;
  int fd;

  /* Determine where the shmfs is mounted.  */
  __libc_once (once, where_is_shmfs);

  /* If we don't know the mount points there is nothing we can do.  Ever.  */
  if (mountpoint.dir == NULL)
    {
      __set_errno (ENOSYS);
      return -1;
    }

  /* Construct the filename.  */
  while (name[0] == '/')
    ++name;

  if (name[0] == '\0')
    {
      /* The name "/" is not supported.  */
      __set_errno (EINVAL);
      return -1;
    }

  namelen = strlen (name);
  fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
  __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
            name, namelen + 1);

#ifdef O_CLOEXEC
  oflag |= O_CLOEXEC;
#endif

  /* And get the file descriptor.
     XXX Maybe we should test each descriptor whether it really is for a
     file on the shmfs.  If this is what should be done the whole function
     should be revamped since we can determine whether shmfs is available
     while trying to open the file, all in one turn.  */
  fd = open (fname, oflag | O_NOFOLLOW, mode);
  if (fd != -1)
    {
#if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
# ifdef O_CLOEXEC
      if (have_o_cloexec <= 0)
# endif
       {
         /* We got a descriptor.  Now set the FD_CLOEXEC bit.  */
         int flags = fcntl (fd, F_GETFD, 0);

         if (__builtin_expect (flags, 0) >= 0)
           {
# ifdef O_CLOEXEC
             if (have_o_cloexec == 0)
              have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
             if (have_o_cloexec < 0)
# endif
              {
                flags |= FD_CLOEXEC;
                flags = fcntl (fd, F_SETFD, flags);
              }
           }

         if (flags == -1)
           {
             /* Something went wrong.  We cannot return the descriptor.  */
             int save_errno = errno;
             close (fd);
             fd = -1;
             __set_errno (save_errno);
           }
       }
#endif
    }
  else if (__builtin_expect (errno == EISDIR, 0))
    /* It might be better to fold this error with EINVAL since
       directory names are just another example for unsuitable shared
       object names and the standard does not mention EISDIR.  */
    __set_errno (EINVAL);

  return fd;
}

Here is the call graph for this function:

int shm_unlink ( const char *  name)

Definition at line 224 of file shm_open.c.

{
  size_t namelen;
  char *fname;

  /* Determine where the shmfs is mounted.  */
  __libc_once (once, where_is_shmfs);

  if (mountpoint.dir == NULL)
    {
      /* We cannot find the shmfs.  If `name' is really a shared
        memory object it must have been created by another process
        and we have no idea where that process found the mountpoint.  */
      __set_errno (ENOENT);
      return -1;
    }

  /* Construct the filename.  */
  while (name[0] == '/')
    ++name;

  if (name[0] == '\0')
    {
      /* The name "/" is not supported.  */
      __set_errno (ENOENT);
      return -1;
    }

  namelen = strlen (name);
  fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
  __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
            name, namelen + 1);

  /* And remove the file.  */
  int ret = unlink (fname);
  if (ret < 0 && errno == EPERM)
    __set_errno (EACCES);
  return ret;
}

Here is the call graph for this function:

static void where_is_shmfs ( void  ) [static]

Definition at line 56 of file shm_open.c.

{
  char buf[512];
  struct statfs f;
  struct mntent resmem;
  struct mntent *mp;
  FILE *fp;

  /* The canonical place is /dev/shm.  This is at least what the
     documentation tells everybody to do.  */
  if (__statfs (defaultdir, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
    {
      /* It is in the normal place.  */
      mountpoint.dir = (char *) defaultdir;
      mountpoint.dirlen = sizeof (defaultdir) - 1;

      return;
    }

  /* OK, do it the hard way.  Look through the /proc/mounts file and if
     this does not exist through /etc/fstab to find the mount point.  */
  fp = __setmntent ("/proc/mounts", "r");
  if (__builtin_expect (fp == NULL, 0))
    {
      fp = __setmntent (_PATH_MNTTAB, "r");
      if (__builtin_expect (fp == NULL, 0))
       /* There is nothing we can do.  Blind guesses are not helpful.  */
       return;
    }

  /* Now read the entries.  */
  while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
    /* The original name is "shm" but this got changed in early Linux
       2.4.x to "tmpfs".  */
    if (strcmp (mp->mnt_type, "tmpfs") == 0
#ifndef __ASSUME_TMPFS_NAME
       || strcmp (mp->mnt_type, "shm") == 0
#endif
       )
      {
       /* Found it.  There might be more than one place where the
           filesystem is mounted but one is enough for us.  */
       size_t namelen;

       /* First make sure this really is the correct entry.  At least
          some versions of the kernel give wrong information because
          of the implicit mount of the shmfs for SysV IPC.  */
       if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
         continue;

       namelen = strlen (mp->mnt_dir);

       if (namelen == 0)
         /* Hum, maybe some crippled entry.  Keep on searching.  */
         continue;

       mountpoint.dir = (char *) malloc (namelen + 2);
       if (mountpoint.dir != NULL)
         {
           char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
           if (cp[-1] != '/')
             *cp++ = '/';
           *cp = '\0';
           mountpoint.dirlen = cp - mountpoint.dir;
         }

       break;
      }

  /* Close the stream.  */
  __endmntent (fp);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char defaultdir[] = "/dev/shm/" [static]

Definition at line 43 of file shm_open.c.

struct { ... } mountpoint [static]