1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP version 4 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: shmop.c 281742 2009-06-06 02:40:49Z mattwil $ */
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 : {NULL, NULL, NULL} /* Must be the last line in shmop_functions[] */
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
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 3 : {
128 3 : struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
129 :
130 3 : shmdt(shmop->addr);
131 3 : efree(shmop);
132 3 : }
133 : /* }}} */
134 :
135 : /* {{{ PHP_MINIT_FUNCTION
136 : */
137 : PHP_MINIT_FUNCTION(shmop)
138 17633 : {
139 17633 : shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
140 :
141 17633 : return SUCCESS;
142 : }
143 : /* }}} */
144 :
145 : /* {{{ PHP_MINFO_FUNCTION
146 : */
147 : PHP_MINFO_FUNCTION(shmop)
148 42 : {
149 42 : php_info_print_table_start();
150 42 : php_info_print_table_row(2, "shmop support", "enabled");
151 42 : php_info_print_table_end();
152 42 : }
153 : /* }}} */
154 :
155 : /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
156 : gets and attaches a shared memory segment */
157 : PHP_FUNCTION(shmop_open)
158 3 : {
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 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
167 0 : return;
168 : }
169 :
170 3 : if (flags_len != 1) {
171 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
172 0 : RETURN_FALSE;
173 : }
174 :
175 3 : shmop = emalloc(sizeof(struct php_shmop));
176 3 : memset(shmop, 0, sizeof(struct php_shmop));
177 :
178 3 : shmop->key = key;
179 3 : shmop->shmflg |= mode;
180 :
181 3 : switch (flags[0])
182 : {
183 : case 'a':
184 1 : shmop->shmatflg |= SHM_RDONLY;
185 1 : break;
186 : case 'c':
187 0 : shmop->shmflg |= IPC_CREAT;
188 0 : shmop->size = size;
189 0 : break;
190 : case 'n':
191 1 : shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
192 1 : shmop->size = size;
193 1 : 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 1 : break;
200 : default:
201 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
202 0 : goto err;
203 : }
204 :
205 3 : if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
206 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
207 0 : goto err;
208 : }
209 :
210 3 : shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
211 3 : if (shmop->shmid == -1) {
212 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
213 0 : goto err;
214 : }
215 :
216 3 : if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
217 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
218 0 : goto err;
219 : }
220 :
221 3 : shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
222 3 : if (shmop->addr == (char*) -1) {
223 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
224 0 : goto err;
225 : }
226 :
227 3 : shmop->size = shm.shm_segsz;
228 :
229 3 : rsid = zend_list_insert(shmop, shm_type);
230 3 : RETURN_LONG(rsid);
231 0 : err:
232 0 : efree(shmop);
233 0 : RETURN_FALSE;
234 : }
235 : /* }}} */
236 :
237 : /* {{{ proto string shmop_read (int shmid, int start, int count)
238 : reads from a shm segment */
239 : PHP_FUNCTION(shmop_read)
240 3 : {
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 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
249 0 : return;
250 : }
251 :
252 3 : PHP_SHMOP_GET_RES
253 :
254 3 : if (start < 0 || start > shmop->size) {
255 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
256 0 : RETURN_FALSE;
257 : }
258 :
259 3 : if (start + count > shmop->size || count < 0) {
260 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
261 0 : RETURN_FALSE;
262 : }
263 :
264 3 : startaddr = shmop->addr + start;
265 3 : bytes = count ? count : shmop->size - start;
266 :
267 3 : return_string = emalloc(bytes+1);
268 3 : memcpy(return_string, startaddr, bytes);
269 3 : return_string[bytes] = 0;
270 :
271 3 : RETURN_STRINGL(return_string, bytes, 0);
272 : }
273 : /* }}} */
274 :
275 : /* {{{ proto void shmop_close (int shmid)
276 : closes a shared memory segment */
277 : PHP_FUNCTION(shmop_close)
278 3 : {
279 : long shmid;
280 : struct php_shmop *shmop;
281 : int type;
282 :
283 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
284 0 : return;
285 : }
286 :
287 3 : PHP_SHMOP_GET_RES
288 :
289 3 : zend_list_delete(shmid);
290 : }
291 : /* }}} */
292 :
293 : /* {{{ proto int shmop_size (int shmid)
294 : returns the shm size */
295 : PHP_FUNCTION(shmop_size)
296 1 : {
297 : long shmid;
298 : struct php_shmop *shmop;
299 : int type;
300 :
301 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
302 0 : return;
303 : }
304 :
305 1 : PHP_SHMOP_GET_RES
306 :
307 1 : 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 */
313 : PHP_FUNCTION(shmop_write)
314 3 : {
315 : struct php_shmop *shmop;
316 : int type;
317 : int writesize;
318 : long shmid, offset;
319 : char *data;
320 : int data_len;
321 :
322 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
323 0 : return;
324 : }
325 :
326 3 : PHP_SHMOP_GET_RES
327 :
328 3 : if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
329 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
330 1 : RETURN_FALSE;
331 : }
332 :
333 2 : if (offset < 0 || offset > shmop->size) {
334 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
335 0 : RETURN_FALSE;
336 : }
337 :
338 2 : writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
339 2 : memcpy(shmop->addr + offset, data, writesize);
340 :
341 2 : RETURN_LONG(writesize);
342 : }
343 : /* }}} */
344 :
345 : /* {{{ proto bool shmop_delete (int shmid)
346 : mark segment for deletion */
347 : PHP_FUNCTION(shmop_delete)
348 1 : {
349 : long shmid;
350 : struct php_shmop *shmop;
351 : int type;
352 :
353 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
354 0 : return;
355 : }
356 :
357 1 : PHP_SHMOP_GET_RES
358 :
359 1 : if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
360 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
361 0 : RETURN_FALSE;
362 : }
363 :
364 1 : 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 : */
|