| /* Copyright (C) 2009 Bernhard Reutner-Fischer <uclibc@uclibc.org> |
| * |
| * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. |
| */ |
| |
| #include <features.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/mman.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| |
| #ifndef _PATH_SHM |
| #define _PATH_SHM "/dev/shm/" |
| #endif |
| |
| #ifndef NAME_MAX |
| #define NAME_MAX 255 |
| #endif |
| |
| /* Get name of dummy shm operation handle. |
| * Returns a malloc'ed buffer containing the OS specific path |
| * to the shm filename or NULL upon failure. |
| */ |
| static __attribute_noinline__ char* get_shm_name(const char *name) __nonnull((1)); |
| static char* get_shm_name(const char *name) |
| { |
| char *path; |
| int i; |
| |
| /* Skip leading slashes */ |
| while (*name == '/') |
| ++name; |
| #ifdef __USE_GNU |
| i = asprintf(&path, _PATH_SHM "%s", name); |
| if (i < 0) |
| return NULL; |
| #else |
| path = malloc(NAME_MAX); |
| if (path == NULL) |
| return NULL; |
| i = snprintf(path, NAME_MAX, _PATH_SHM "%s", name); |
| if (i < 0) { |
| free(path); |
| return NULL; |
| } else if (i >= NAME_MAX) { |
| free(path); |
| __set_errno(ENAMETOOLONG); |
| return NULL; |
| } |
| #endif |
| return path; |
| } |
| |
| int shm_open(const char *name, int oflag, mode_t mode) |
| { |
| int fd; |
| char *shm_name = get_shm_name(name); |
| |
| /* Stripped multiple '/' from start; may have set errno properly */ |
| if (shm_name == NULL) |
| return -1; |
| /* The FD_CLOEXEC file descriptor flag associated with the new |
| * file descriptor is set. */ |
| #ifdef O_CLOEXEC |
| /* Just open it with CLOEXEC set, for brevity */ |
| fd = open(shm_name, oflag | O_CLOEXEC, mode); |
| #else |
| fd = open(shm_name, oflag, mode); |
| if (fd >= 0) { |
| fcntl(fd, F_SETFD, FD_CLOEXEC); |
| /* thus far, {G,S}ETFD only has this single flag, |
| * and setting it never fails. |
| *int fdflags = fcntl(fd, F_GETFD); |
| *if (fdflags >= 0) |
| * fdflags = fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC); |
| *if (fdflags < 0) { |
| * close(fd); |
| * fd = -1; |
| *} |
| */ |
| } |
| #endif |
| free(shm_name); /* doesn't affect errno */ |
| return fd; |
| } |
| |
| int shm_unlink(const char *name) |
| { |
| char *shm_name = get_shm_name(name); |
| int ret; |
| |
| /* Stripped multiple '/' from start; may have set errno properly */ |
| if (shm_name == NULL) |
| return -1; |
| ret = unlink(shm_name); |
| free(shm_name); /* doesn't affect errno */ |
| return ret; |
| } |