shm.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /* Copyright (C) 2009 Bernhard Reutner-Fischer <uclibc@uclibc.org>
  2. *
  3. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  4. */
  5. #include <features.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/mman.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <errno.h>
  14. #ifndef _PATH_SHM
  15. #define _PATH_SHM "/dev/shm/"
  16. #endif
  17. #ifndef NAME_MAX
  18. #define NAME_MAX 255
  19. #endif
  20. /* Get name of dummy shm operation handle.
  21. * Returns a malloc'ed buffer containing the OS specific path
  22. * to the shm filename or NULL upon failure.
  23. */
  24. static __attribute_noinline__ char* get_shm_name(const char *name) __nonnull((1));
  25. static char* get_shm_name(const char *name)
  26. {
  27. char *path;
  28. int i;
  29. /* Skip leading slashes */
  30. while (*name == '/')
  31. ++name;
  32. #ifdef __USE_GNU
  33. i = asprintf(&path, _PATH_SHM "%s", name);
  34. if (i < 0)
  35. return NULL;
  36. #else
  37. path = malloc(NAME_MAX);
  38. if (path == NULL)
  39. return NULL;
  40. i = snprintf(path, NAME_MAX, _PATH_SHM "%s", name);
  41. if (i < 0) {
  42. free(path);
  43. return NULL;
  44. } else if (i >= NAME_MAX) {
  45. free(path);
  46. __set_errno(ENAMETOOLONG);
  47. return NULL;
  48. }
  49. #endif
  50. return path;
  51. }
  52. int shm_open(const char *name, int oflag, mode_t mode)
  53. {
  54. int fd;
  55. char *shm_name = get_shm_name(name);
  56. /* Stripped multiple '/' from start; may have set errno properly */
  57. if (shm_name == NULL)
  58. return -1;
  59. /* The FD_CLOEXEC file descriptor flag associated with the new
  60. * file descriptor is set. */
  61. #ifdef O_CLOEXEC
  62. /* Just open it with CLOEXEC set, for brevity */
  63. fd = open(shm_name, oflag | O_CLOEXEC, mode);
  64. #else
  65. fd = open(shm_name, oflag, mode);
  66. if (fd >= 0) {
  67. fcntl(fd, F_SETFD, FD_CLOEXEC);
  68. /* thus far, {G,S}ETFD only has this single flag,
  69. * and setting it never fails.
  70. *int fdflags = fcntl(fd, F_GETFD);
  71. *if (fdflags >= 0)
  72. * fdflags = fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC);
  73. *if (fdflags < 0) {
  74. * close(fd);
  75. * fd = -1;
  76. *}
  77. */
  78. }
  79. #endif
  80. if (fd < 0 && errno == EISDIR)
  81. /* EISDIR is not valid for shm_open, replace it with EINVAL as glibc. */
  82. __set_errno (EINVAL);
  83. free(shm_name); /* doesn't affect errno */
  84. return fd;
  85. }
  86. int shm_unlink(const char *name)
  87. {
  88. char *shm_name = get_shm_name(name);
  89. int ret;
  90. /* Stripped multiple '/' from start; may have set errno properly */
  91. if (shm_name == NULL)
  92. return -1;
  93. ret = unlink(shm_name);
  94. free(shm_name); /* doesn't affect errno */
  95. return ret;
  96. }