Back to index

glibc  2.9
shm_open.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000-2004,2006,2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <fcntl.h>
00021 #include <mntent.h>
00022 #include <paths.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <sys/mman.h>
00028 #include <sys/statfs.h>
00029 #include <bits/libc-lock.h>
00030 #include "linux_fsinfo.h"
00031 
00032 #include <kernel-features.h>
00033 
00034 
00035 /* Mount point of the shared memory filesystem.  */
00036 static struct
00037 {
00038   char *dir;
00039   size_t dirlen;
00040 } mountpoint;
00041 
00042 /* This is the default directory.  */
00043 static const char defaultdir[] = "/dev/shm/";
00044 
00045 /* Protect the `mountpoint' variable above.  */
00046 __libc_once_define (static, once);
00047 
00048 
00049 #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
00050 static bool have_o_cloexec;
00051 #endif
00052 
00053 
00054 /* Determine where the shmfs is mounted (if at all).  */
00055 static void
00056 where_is_shmfs (void)
00057 {
00058   char buf[512];
00059   struct statfs f;
00060   struct mntent resmem;
00061   struct mntent *mp;
00062   FILE *fp;
00063 
00064   /* The canonical place is /dev/shm.  This is at least what the
00065      documentation tells everybody to do.  */
00066   if (__statfs (defaultdir, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
00067     {
00068       /* It is in the normal place.  */
00069       mountpoint.dir = (char *) defaultdir;
00070       mountpoint.dirlen = sizeof (defaultdir) - 1;
00071 
00072       return;
00073     }
00074 
00075   /* OK, do it the hard way.  Look through the /proc/mounts file and if
00076      this does not exist through /etc/fstab to find the mount point.  */
00077   fp = __setmntent ("/proc/mounts", "r");
00078   if (__builtin_expect (fp == NULL, 0))
00079     {
00080       fp = __setmntent (_PATH_MNTTAB, "r");
00081       if (__builtin_expect (fp == NULL, 0))
00082        /* There is nothing we can do.  Blind guesses are not helpful.  */
00083        return;
00084     }
00085 
00086   /* Now read the entries.  */
00087   while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
00088     /* The original name is "shm" but this got changed in early Linux
00089        2.4.x to "tmpfs".  */
00090     if (strcmp (mp->mnt_type, "tmpfs") == 0
00091 #ifndef __ASSUME_TMPFS_NAME
00092        || strcmp (mp->mnt_type, "shm") == 0
00093 #endif
00094        )
00095       {
00096        /* Found it.  There might be more than one place where the
00097            filesystem is mounted but one is enough for us.  */
00098        size_t namelen;
00099 
00100        /* First make sure this really is the correct entry.  At least
00101           some versions of the kernel give wrong information because
00102           of the implicit mount of the shmfs for SysV IPC.  */
00103        if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
00104          continue;
00105 
00106        namelen = strlen (mp->mnt_dir);
00107 
00108        if (namelen == 0)
00109          /* Hum, maybe some crippled entry.  Keep on searching.  */
00110          continue;
00111 
00112        mountpoint.dir = (char *) malloc (namelen + 2);
00113        if (mountpoint.dir != NULL)
00114          {
00115            char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
00116            if (cp[-1] != '/')
00117              *cp++ = '/';
00118            *cp = '\0';
00119            mountpoint.dirlen = cp - mountpoint.dir;
00120          }
00121 
00122        break;
00123       }
00124 
00125   /* Close the stream.  */
00126   __endmntent (fp);
00127 }
00128 
00129 
00130 /* Open shared memory object.  This implementation assumes the shmfs
00131    implementation introduced in the late 2.3.x kernel series to be
00132    available.  Normally the filesystem will be mounted at /dev/shm but
00133    we fall back on searching for the actual mount point should opening
00134    such a file fail.  */
00135 int
00136 shm_open (const char *name, int oflag, mode_t mode)
00137 {
00138   size_t namelen;
00139   char *fname;
00140   int fd;
00141 
00142   /* Determine where the shmfs is mounted.  */
00143   __libc_once (once, where_is_shmfs);
00144 
00145   /* If we don't know the mount points there is nothing we can do.  Ever.  */
00146   if (mountpoint.dir == NULL)
00147     {
00148       __set_errno (ENOSYS);
00149       return -1;
00150     }
00151 
00152   /* Construct the filename.  */
00153   while (name[0] == '/')
00154     ++name;
00155 
00156   if (name[0] == '\0')
00157     {
00158       /* The name "/" is not supported.  */
00159       __set_errno (EINVAL);
00160       return -1;
00161     }
00162 
00163   namelen = strlen (name);
00164   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
00165   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
00166             name, namelen + 1);
00167 
00168 #ifdef O_CLOEXEC
00169   oflag |= O_CLOEXEC;
00170 #endif
00171 
00172   /* And get the file descriptor.
00173      XXX Maybe we should test each descriptor whether it really is for a
00174      file on the shmfs.  If this is what should be done the whole function
00175      should be revamped since we can determine whether shmfs is available
00176      while trying to open the file, all in one turn.  */
00177   fd = open (fname, oflag | O_NOFOLLOW, mode);
00178   if (fd != -1)
00179     {
00180 #if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
00181 # ifdef O_CLOEXEC
00182       if (have_o_cloexec <= 0)
00183 # endif
00184        {
00185          /* We got a descriptor.  Now set the FD_CLOEXEC bit.  */
00186          int flags = fcntl (fd, F_GETFD, 0);
00187 
00188          if (__builtin_expect (flags, 0) >= 0)
00189            {
00190 # ifdef O_CLOEXEC
00191              if (have_o_cloexec == 0)
00192               have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
00193              if (have_o_cloexec < 0)
00194 # endif
00195               {
00196                 flags |= FD_CLOEXEC;
00197                 flags = fcntl (fd, F_SETFD, flags);
00198               }
00199            }
00200 
00201          if (flags == -1)
00202            {
00203              /* Something went wrong.  We cannot return the descriptor.  */
00204              int save_errno = errno;
00205              close (fd);
00206              fd = -1;
00207              __set_errno (save_errno);
00208            }
00209        }
00210 #endif
00211     }
00212   else if (__builtin_expect (errno == EISDIR, 0))
00213     /* It might be better to fold this error with EINVAL since
00214        directory names are just another example for unsuitable shared
00215        object names and the standard does not mention EISDIR.  */
00216     __set_errno (EINVAL);
00217 
00218   return fd;
00219 }
00220 
00221 
00222 /* Unlink a shared memory object.  */
00223 int
00224 shm_unlink (const char *name)
00225 {
00226   size_t namelen;
00227   char *fname;
00228 
00229   /* Determine where the shmfs is mounted.  */
00230   __libc_once (once, where_is_shmfs);
00231 
00232   if (mountpoint.dir == NULL)
00233     {
00234       /* We cannot find the shmfs.  If `name' is really a shared
00235         memory object it must have been created by another process
00236         and we have no idea where that process found the mountpoint.  */
00237       __set_errno (ENOENT);
00238       return -1;
00239     }
00240 
00241   /* Construct the filename.  */
00242   while (name[0] == '/')
00243     ++name;
00244 
00245   if (name[0] == '\0')
00246     {
00247       /* The name "/" is not supported.  */
00248       __set_errno (ENOENT);
00249       return -1;
00250     }
00251 
00252   namelen = strlen (name);
00253   fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
00254   __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
00255             name, namelen + 1);
00256 
00257   /* And remove the file.  */
00258   int ret = unlink (fname);
00259   if (ret < 0 && errno == EPERM)
00260     __set_errno (EACCES);
00261   return ret;
00262 }
00263 
00264 
00265 /* Make sure the table is freed if we want to free everything before
00266    exiting.  */
00267 libc_freeres_fn (freeit)
00268 {
00269   if (mountpoint.dir != defaultdir)
00270     free (mountpoint.dir);
00271 }