| /* 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; | 
 | } |