-/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2000-2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <fcntl.h>
#include <bits/libc-lock.h>
#include "linux_fsinfo.h"
+#include <kernel-features.h>
+
/* Mount point of the shared memory filesystem. */
static struct
__libc_once_define (static, once);
+#if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
+static bool have_o_cloexec;
+#endif
+
+
/* Determine where the shmfs is mounted (if at all). */
static void
where_is_shmfs (void)
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)
- || (strcmp (mp->mnt_type, "shm")))
+ if (strcmp (mp->mnt_type, "tmpfs") == 0)
{
/* Found it. There might be more than one place where the
filesystem is mounted but one is enough for us. */
while (name[0] == '/')
++name;
- if (name[0] == '\0')
+ namelen = strlen (name);
+
+ /* Validate the filename. */
+ if (name[0] == '\0' || namelen > NAME_MAX || strchr (name, '/') != NULL)
{
- /* 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
fd = open (fname, oflag | O_NOFOLLOW, mode);
if (fd != -1)
{
- /* We got a descriptor. Now set the FD_CLOEXEC bit. */
- int flags = fcntl (fd, F_GETFD, 0);
-
- if (__builtin_expect (flags, 0) >= 0)
- {
- flags |= FD_CLOEXEC;
- flags = fcntl (fd, F_SETFD, flags);
- }
-
- if (flags == -1)
+#if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
+# ifdef O_CLOEXEC
+ if (have_o_cloexec <= 0)
+# endif
{
- /* Something went wrong. We cannot return the descriptor. */
- int save_errno = errno;
- close (fd);
- fd = -1;
- __set_errno (save_errno);
+ /* 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;
}
while (name[0] == '/')
++name;
- if (name[0] == '\0')
+ namelen = strlen (name);
+
+ /* Validate the filename. */
+ if (name[0] == '\0' || namelen > NAME_MAX || strchr (name, '/') != NULL)
{
- /* 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. */
- return unlink (fname);
+ int ret = unlink (fname);
+ if (ret < 0 && errno == EPERM)
+ __set_errno (EACCES);
+ return ret;
}
-static void __attribute__ ((unused))
-freeit (void)
+/* Make sure the table is freed if we want to free everything before
+ exiting. */
+libc_freeres_fn (freeit)
{
if (mountpoint.dir != defaultdir)
free (mountpoint.dir);
}
-
-
-/* Make sure the table is freed if we want to free everything before
- exiting. */
-text_set_element (__libc_subfreeres, freeit);