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