shmop.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Slava Poliakov <hackie@prohost.org> |
  16. | Ilia Alshanetsky <ilia@prohost.org> |
  17. +----------------------------------------------------------------------+
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #include "php_shmop.h"
  25. # ifndef PHP_WIN32
  26. # include <sys/ipc.h>
  27. # include <sys/shm.h>
  28. #else
  29. #include "tsrm_win32.h"
  30. #endif
  31. #if HAVE_SHMOP
  32. #include "ext/standard/info.h"
  33. #ifdef ZTS
  34. int shmop_globals_id;
  35. #else
  36. php_shmop_globals shmop_globals;
  37. #endif
  38. int shm_type;
  39. /* {{{ arginfo */
  40. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_open, 0, 0, 4)
  41. ZEND_ARG_INFO(0, key)
  42. ZEND_ARG_INFO(0, flags)
  43. ZEND_ARG_INFO(0, mode)
  44. ZEND_ARG_INFO(0, size)
  45. ZEND_END_ARG_INFO()
  46. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_read, 0, 0, 3)
  47. ZEND_ARG_INFO(0, shmid)
  48. ZEND_ARG_INFO(0, start)
  49. ZEND_ARG_INFO(0, count)
  50. ZEND_END_ARG_INFO()
  51. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_close, 0, 0, 1)
  52. ZEND_ARG_INFO(0, shmid)
  53. ZEND_END_ARG_INFO()
  54. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_size, 0, 0, 1)
  55. ZEND_ARG_INFO(0, shmid)
  56. ZEND_END_ARG_INFO()
  57. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_write, 0, 0, 3)
  58. ZEND_ARG_INFO(0, shmid)
  59. ZEND_ARG_INFO(0, data)
  60. ZEND_ARG_INFO(0, offset)
  61. ZEND_END_ARG_INFO()
  62. ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_delete, 0, 0, 1)
  63. ZEND_ARG_INFO(0, shmid)
  64. ZEND_END_ARG_INFO()
  65. /* }}} */
  66. /* {{{ shmop_functions[]
  67. */
  68. static const zend_function_entry shmop_functions[] = {
  69. PHP_FE(shmop_open, arginfo_shmop_open)
  70. PHP_FE(shmop_read, arginfo_shmop_read)
  71. PHP_FE(shmop_close, arginfo_shmop_close)
  72. PHP_FE(shmop_size, arginfo_shmop_size)
  73. PHP_FE(shmop_write, arginfo_shmop_write)
  74. PHP_FE(shmop_delete, arginfo_shmop_delete)
  75. PHP_FE_END
  76. };
  77. /* }}} */
  78. /* {{{ shmop_module_entry
  79. */
  80. zend_module_entry shmop_module_entry = {
  81. STANDARD_MODULE_HEADER,
  82. "shmop",
  83. shmop_functions,
  84. PHP_MINIT(shmop),
  85. NULL,
  86. NULL,
  87. NULL,
  88. PHP_MINFO(shmop),
  89. PHP_SHMOP_VERSION,
  90. STANDARD_MODULE_PROPERTIES
  91. };
  92. /* }}} */
  93. #ifdef COMPILE_DL_SHMOP
  94. ZEND_GET_MODULE(shmop)
  95. #endif
  96. /* {{{ rsclean
  97. */
  98. static void rsclean(zend_resource *rsrc)
  99. {
  100. struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
  101. shmdt(shmop->addr);
  102. efree(shmop);
  103. }
  104. /* }}} */
  105. /* {{{ PHP_MINIT_FUNCTION
  106. */
  107. PHP_MINIT_FUNCTION(shmop)
  108. {
  109. shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
  110. return SUCCESS;
  111. }
  112. /* }}} */
  113. /* {{{ PHP_MINFO_FUNCTION
  114. */
  115. PHP_MINFO_FUNCTION(shmop)
  116. {
  117. php_info_print_table_start();
  118. php_info_print_table_row(2, "shmop support", "enabled");
  119. php_info_print_table_end();
  120. }
  121. /* }}} */
  122. /* {{{ proto resource shmop_open(int key, string flags, int mode, int size)
  123. gets and attaches a shared memory segment */
  124. PHP_FUNCTION(shmop_open)
  125. {
  126. zend_long key, mode, size;
  127. struct php_shmop *shmop;
  128. struct shmid_ds shm;
  129. char *flags;
  130. size_t flags_len;
  131. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
  132. return;
  133. }
  134. if (flags_len != 1) {
  135. php_error_docref(NULL, E_WARNING, "%s is not a valid flag", flags);
  136. RETURN_FALSE;
  137. }
  138. shmop = emalloc(sizeof(struct php_shmop));
  139. memset(shmop, 0, sizeof(struct php_shmop));
  140. shmop->key = key;
  141. shmop->shmflg |= mode;
  142. switch (flags[0])
  143. {
  144. case 'a':
  145. shmop->shmatflg |= SHM_RDONLY;
  146. break;
  147. case 'c':
  148. shmop->shmflg |= IPC_CREAT;
  149. shmop->size = size;
  150. break;
  151. case 'n':
  152. shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
  153. shmop->size = size;
  154. break;
  155. case 'w':
  156. /* noop
  157. shm segment is being opened for read & write
  158. will fail if segment does not exist
  159. */
  160. break;
  161. default:
  162. php_error_docref(NULL, E_WARNING, "invalid access mode");
  163. goto err;
  164. }
  165. if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
  166. php_error_docref(NULL, E_WARNING, "Shared memory segment size must be greater than zero");
  167. goto err;
  168. }
  169. shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
  170. if (shmop->shmid == -1) {
  171. php_error_docref(NULL, E_WARNING, "unable to attach or create shared memory segment '%s'", strerror(errno));
  172. goto err;
  173. }
  174. if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
  175. /* please do not add coverage here: the segment would be leaked and impossible to delete via php */
  176. php_error_docref(NULL, E_WARNING, "unable to get shared memory segment information '%s'", strerror(errno));
  177. goto err;
  178. }
  179. if (shm.shm_segsz > ZEND_LONG_MAX) {
  180. php_error_docref(NULL, E_WARNING, "shared memory segment too large to attach");
  181. goto err;
  182. }
  183. shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
  184. if (shmop->addr == (char*) -1) {
  185. php_error_docref(NULL, E_WARNING, "unable to attach to shared memory segment '%s'", strerror(errno));
  186. goto err;
  187. }
  188. shmop->size = shm.shm_segsz;
  189. RETURN_RES(zend_register_resource(shmop, shm_type));
  190. err:
  191. efree(shmop);
  192. RETURN_FALSE;
  193. }
  194. /* }}} */
  195. /* {{{ proto string shmop_read(resource shmid, int start, int count)
  196. reads from a shm segment */
  197. PHP_FUNCTION(shmop_read)
  198. {
  199. zval *shmid;
  200. zend_long start, count;
  201. struct php_shmop *shmop;
  202. char *startaddr;
  203. int bytes;
  204. zend_string *return_string;
  205. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rll", &shmid, &start, &count) == FAILURE) {
  206. return;
  207. }
  208. if ((shmop = (struct php_shmop *)zend_fetch_resource(Z_RES_P(shmid), "shmop", shm_type)) == NULL) {
  209. RETURN_FALSE;
  210. }
  211. if (start < 0 || start > shmop->size) {
  212. php_error_docref(NULL, E_WARNING, "start is out of range");
  213. RETURN_FALSE;
  214. }
  215. if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) {
  216. php_error_docref(NULL, E_WARNING, "count is out of range");
  217. RETURN_FALSE;
  218. }
  219. startaddr = shmop->addr + start;
  220. bytes = count ? count : shmop->size - start;
  221. return_string = zend_string_init(startaddr, bytes, 0);
  222. RETURN_NEW_STR(return_string);
  223. }
  224. /* }}} */
  225. /* {{{ proto void shmop_close(resource shmid)
  226. closes a shared memory segment */
  227. PHP_FUNCTION(shmop_close)
  228. {
  229. zval *shmid;
  230. struct php_shmop *shmop;
  231. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &shmid) == FAILURE) {
  232. return;
  233. }
  234. if ((shmop = (struct php_shmop *)zend_fetch_resource(Z_RES_P(shmid), "shmop", shm_type)) == NULL) {
  235. RETURN_FALSE;
  236. }
  237. zend_list_close(Z_RES_P(shmid));
  238. }
  239. /* }}} */
  240. /* {{{ proto int shmop_size(resource shmid)
  241. returns the shm size */
  242. PHP_FUNCTION(shmop_size)
  243. {
  244. zval *shmid;
  245. struct php_shmop *shmop;
  246. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &shmid) == FAILURE) {
  247. return;
  248. }
  249. if ((shmop = (struct php_shmop *)zend_fetch_resource(Z_RES_P(shmid), "shmop", shm_type)) == NULL) {
  250. RETURN_FALSE;
  251. }
  252. RETURN_LONG(shmop->size);
  253. }
  254. /* }}} */
  255. /* {{{ proto int shmop_write(resource shmid, string data, int offset)
  256. writes to a shared memory segment */
  257. PHP_FUNCTION(shmop_write)
  258. {
  259. struct php_shmop *shmop;
  260. zend_long writesize;
  261. zend_long offset;
  262. zend_string *data;
  263. zval *shmid;
  264. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSl", &shmid, &data, &offset) == FAILURE) {
  265. return;
  266. }
  267. if ((shmop = (struct php_shmop *)zend_fetch_resource(Z_RES_P(shmid), "shmop", shm_type)) == NULL) {
  268. RETURN_FALSE;
  269. }
  270. if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
  271. php_error_docref(NULL, E_WARNING, "trying to write to a read only segment");
  272. RETURN_FALSE;
  273. }
  274. if (offset < 0 || offset > shmop->size) {
  275. php_error_docref(NULL, E_WARNING, "offset out of range");
  276. RETURN_FALSE;
  277. }
  278. writesize = ((zend_long)ZSTR_LEN(data) < shmop->size - offset) ? (zend_long)ZSTR_LEN(data) : shmop->size - offset;
  279. memcpy(shmop->addr + offset, ZSTR_VAL(data), writesize);
  280. RETURN_LONG(writesize);
  281. }
  282. /* }}} */
  283. /* {{{ proto bool shmop_delete(resource shmid)
  284. mark segment for deletion */
  285. PHP_FUNCTION(shmop_delete)
  286. {
  287. zval *shmid;
  288. struct php_shmop *shmop;
  289. if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &shmid) == FAILURE) {
  290. return;
  291. }
  292. if ((shmop = (struct php_shmop *)zend_fetch_resource(Z_RES_P(shmid), "shmop", shm_type)) == NULL) {
  293. RETURN_FALSE;
  294. }
  295. if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
  296. php_error_docref(NULL, E_WARNING, "can't mark segment for deletion (are you the owner?)");
  297. RETURN_FALSE;
  298. }
  299. RETURN_TRUE;
  300. }
  301. /* }}} */
  302. #endif /* HAVE_SHMOP */
  303. /*
  304. * Local variables:
  305. * tab-width: 4
  306. * c-basic-offset: 4
  307. * End:
  308. * vim600: sw=4 ts=4 fdm=marker
  309. * vim<600: sw=4 ts=4
  310. */