xref: /PHP-5.5/ext/shmop/shmop.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 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 	NO_VERSION_YET,
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 #define PHP_SHMOP_GET_RES \
115 	shmop = zend_list_find(shmid, &type);	\
116 	if (!shmop) {	\
117 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid);	\
118 		RETURN_FALSE;	\
119 	} else if (type != shm_type) {	\
120 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a shmop resource");	\
121 		RETURN_FALSE;	\
122 	}	\
123 
124 /* {{{ rsclean
125  */
126 static void rsclean(zend_rsrc_list_entry *rsrc TSRMLS_DC)
127 {
128 	struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
129 
130 	shmdt(shmop->addr);
131 	efree(shmop);
132 }
133 /* }}} */
134 
135 /* {{{ PHP_MINIT_FUNCTION
136  */
PHP_MINIT_FUNCTION(shmop)137 PHP_MINIT_FUNCTION(shmop)
138 {
139 	shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
140 
141 	return SUCCESS;
142 }
143 /* }}} */
144 
145 /* {{{ PHP_MINFO_FUNCTION
146  */
PHP_MINFO_FUNCTION(shmop)147 PHP_MINFO_FUNCTION(shmop)
148 {
149 	php_info_print_table_start();
150 	php_info_print_table_row(2, "shmop support", "enabled");
151 	php_info_print_table_end();
152 }
153 /* }}} */
154 
155 /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
156    gets and attaches a shared memory segment */
PHP_FUNCTION(shmop_open)157 PHP_FUNCTION(shmop_open)
158 {
159 	long key, mode, size;
160 	struct php_shmop *shmop;
161 	struct shmid_ds shm;
162 	int rsid;
163 	char *flags;
164 	int flags_len;
165 
166 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
167 		return;
168 	}
169 
170 	if (flags_len != 1) {
171 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
172 		RETURN_FALSE;
173 	}
174 
175 	shmop = emalloc(sizeof(struct php_shmop));
176 	memset(shmop, 0, sizeof(struct php_shmop));
177 
178 	shmop->key = key;
179 	shmop->shmflg |= mode;
180 
181 	switch (flags[0])
182 	{
183 		case 'a':
184 			shmop->shmatflg |= SHM_RDONLY;
185 			break;
186 		case 'c':
187 			shmop->shmflg |= IPC_CREAT;
188 			shmop->size = size;
189 			break;
190 		case 'n':
191 			shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
192 			shmop->size = size;
193 			break;
194 		case 'w':
195 			/* noop
196 				shm segment is being opened for read & write
197 				will fail if segment does not exist
198 			*/
199 			break;
200 		default:
201 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
202 			goto err;
203 	}
204 
205 	if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
206 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
207 		goto err;
208 	}
209 
210 	shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
211 	if (shmop->shmid == -1) {
212 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
213 		goto err;
214 	}
215 
216 	if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
217 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
218 		goto err;
219 	}
220 
221 	shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
222 	if (shmop->addr == (char*) -1) {
223 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
224 		goto err;
225 	}
226 
227 	shmop->size = shm.shm_segsz;
228 
229 	rsid = zend_list_insert(shmop, shm_type TSRMLS_CC);
230 	RETURN_LONG(rsid);
231 err:
232 	efree(shmop);
233 	RETURN_FALSE;
234 }
235 /* }}} */
236 
237 /* {{{ proto string shmop_read (int shmid, int start, int count)
238    reads from a shm segment */
PHP_FUNCTION(shmop_read)239 PHP_FUNCTION(shmop_read)
240 {
241 	long shmid, start, count;
242 	struct php_shmop *shmop;
243 	int type;
244 	char *startaddr;
245 	int bytes;
246 	char *return_string;
247 
248 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
249 		return;
250 	}
251 
252 	PHP_SHMOP_GET_RES
253 
254 	if (start < 0 || start > shmop->size) {
255 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
256 		RETURN_FALSE;
257 	}
258 
259 	if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) {
260 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
261 		RETURN_FALSE;
262 	}
263 
264 	startaddr = shmop->addr + start;
265 	bytes = count ? count : shmop->size - start;
266 
267 	return_string = emalloc(bytes+1);
268 	memcpy(return_string, startaddr, bytes);
269 	return_string[bytes] = 0;
270 
271 	RETURN_STRINGL(return_string, bytes, 0);
272 }
273 /* }}} */
274 
275 /* {{{ proto void shmop_close (int shmid)
276    closes a shared memory segment */
PHP_FUNCTION(shmop_close)277 PHP_FUNCTION(shmop_close)
278 {
279 	long shmid;
280 	struct php_shmop *shmop;
281 	int type;
282 
283 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
284 		return;
285 	}
286 
287 	PHP_SHMOP_GET_RES
288 
289 	zend_list_delete(shmid);
290 }
291 /* }}} */
292 
293 /* {{{ proto int shmop_size (int shmid)
294    returns the shm size */
PHP_FUNCTION(shmop_size)295 PHP_FUNCTION(shmop_size)
296 {
297 	long shmid;
298 	struct php_shmop *shmop;
299 	int type;
300 
301 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
302 		return;
303 	}
304 
305 	PHP_SHMOP_GET_RES
306 
307 	RETURN_LONG(shmop->size);
308 }
309 /* }}} */
310 
311 /* {{{ proto int shmop_write (int shmid, string data, int offset)
312    writes to a shared memory segment */
PHP_FUNCTION(shmop_write)313 PHP_FUNCTION(shmop_write)
314 {
315 	struct php_shmop *shmop;
316 	int type;
317 	int writesize;
318 	long shmid, offset;
319 	char *data;
320 	int data_len;
321 
322 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
323 		return;
324 	}
325 
326 	PHP_SHMOP_GET_RES
327 
328 	if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
329 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
330 		RETURN_FALSE;
331 	}
332 
333 	if (offset < 0 || offset > shmop->size) {
334 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
335 		RETURN_FALSE;
336 	}
337 
338 	writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
339 	memcpy(shmop->addr + offset, data, writesize);
340 
341 	RETURN_LONG(writesize);
342 }
343 /* }}} */
344 
345 /* {{{ proto bool shmop_delete (int shmid)
346    mark segment for deletion */
PHP_FUNCTION(shmop_delete)347 PHP_FUNCTION(shmop_delete)
348 {
349 	long shmid;
350 	struct php_shmop *shmop;
351 	int type;
352 
353 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
354 		return;
355 	}
356 
357 	PHP_SHMOP_GET_RES
358 
359 	if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
360 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
361 		RETURN_FALSE;
362 	}
363 
364 	RETURN_TRUE;
365 }
366 /* }}} */
367 
368 #endif	/* HAVE_SHMOP */
369 
370 /*
371  * Local variables:
372  * tab-width: 4
373  * c-basic-offset: 4
374  * End:
375  * vim600: sw=4 ts=4 fdm=marker
376  * vim<600: sw=4 ts=4
377  */
378