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 272374 2008-12-31 11:17:49Z sebastian $ */
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 : /* {{{ shmop_functions[]
49 : */
50 : zend_function_entry shmop_functions[] = {
51 : PHP_FE(shmop_open, NULL)
52 : PHP_FE(shmop_read, NULL)
53 : PHP_FE(shmop_close, NULL)
54 : PHP_FE(shmop_size, NULL)
55 : PHP_FE(shmop_write, NULL)
56 : PHP_FE(shmop_delete, NULL)
57 : {NULL, NULL, NULL} /* Must be the last line in shmop_functions[] */
58 : };
59 : /* }}} */
60 :
61 : /* {{{ shmop_module_entry
62 : */
63 : zend_module_entry shmop_module_entry = {
64 : STANDARD_MODULE_HEADER,
65 : "shmop",
66 : shmop_functions,
67 : PHP_MINIT(shmop),
68 : NULL,
69 : NULL,
70 : NULL,
71 : PHP_MINFO(shmop),
72 : NO_VERSION_YET,
73 : STANDARD_MODULE_PROPERTIES
74 : };
75 : /* }}} */
76 :
77 : #ifdef COMPILE_DL_SHMOP
78 : ZEND_GET_MODULE(shmop)
79 : #endif
80 :
81 : #define PHP_SHMOP_GET_RES \
82 : shmop = zend_list_find(shmid, &type); \
83 : if (!shmop) { \
84 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid); \
85 : RETURN_FALSE; \
86 : } else if (type != shm_type) { \
87 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a shmop resource"); \
88 : RETURN_FALSE; \
89 : } \
90 :
91 : /* {{{ rsclean
92 : */
93 : static void rsclean(zend_rsrc_list_entry *rsrc TSRMLS_DC)
94 3 : {
95 3 : struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
96 :
97 3 : shmdt(shmop->addr);
98 3 : efree(shmop);
99 3 : }
100 : /* }}} */
101 :
102 : /* {{{ PHP_MINIT_FUNCTION
103 : */
104 : PHP_MINIT_FUNCTION(shmop)
105 13565 : {
106 13565 : shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
107 :
108 13565 : return SUCCESS;
109 : }
110 : /* }}} */
111 :
112 : /* {{{ PHP_MINFO_FUNCTION
113 : */
114 : PHP_MINFO_FUNCTION(shmop)
115 6 : {
116 6 : php_info_print_table_start();
117 6 : php_info_print_table_row(2, "shmop support", "enabled");
118 6 : php_info_print_table_end();
119 6 : }
120 : /* }}} */
121 :
122 : /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
123 : gets and attaches a shared memory segment */
124 : PHP_FUNCTION(shmop_open)
125 3 : {
126 : long key, mode, size;
127 : struct php_shmop *shmop;
128 : struct shmid_ds shm;
129 : int rsid;
130 : char *flags;
131 : int flags_len;
132 :
133 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
134 0 : return;
135 : }
136 :
137 3 : if (flags_len != 1) {
138 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
139 0 : RETURN_FALSE;
140 : }
141 :
142 3 : shmop = emalloc(sizeof(struct php_shmop));
143 3 : memset(shmop, 0, sizeof(struct php_shmop));
144 :
145 3 : shmop->key = key;
146 3 : shmop->shmflg |= mode;
147 :
148 3 : switch (flags[0])
149 : {
150 : case 'a':
151 1 : shmop->shmatflg |= SHM_RDONLY;
152 1 : break;
153 : case 'c':
154 0 : shmop->shmflg |= IPC_CREAT;
155 0 : shmop->size = size;
156 0 : break;
157 : case 'n':
158 1 : shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
159 1 : shmop->size = size;
160 1 : break;
161 : case 'w':
162 : /* noop
163 : shm segment is being opened for read & write
164 : will fail if segment does not exist
165 : */
166 1 : break;
167 : default:
168 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
169 0 : goto err;
170 : }
171 :
172 3 : if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
173 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater then zero.");
174 0 : goto err;
175 : }
176 :
177 3 : shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
178 3 : if (shmop->shmid == -1) {
179 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
180 0 : goto err;
181 : }
182 :
183 3 : if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
184 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
185 0 : goto err;
186 : }
187 :
188 3 : shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
189 3 : if (shmop->addr == (char*) -1) {
190 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
191 0 : goto err;
192 : }
193 :
194 3 : shmop->size = shm.shm_segsz;
195 :
196 3 : rsid = zend_list_insert(shmop, shm_type);
197 3 : RETURN_LONG(rsid);
198 0 : err:
199 0 : efree(shmop);
200 0 : RETURN_FALSE;
201 : }
202 : /* }}} */
203 :
204 : /* {{{ proto string shmop_read (int shmid, int start, int count)
205 : reads from a shm segment */
206 : PHP_FUNCTION(shmop_read)
207 3 : {
208 : long shmid, start, count;
209 : struct php_shmop *shmop;
210 : int type;
211 : char *startaddr;
212 : int bytes;
213 : char *return_string;
214 :
215 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
216 0 : return;
217 : }
218 :
219 3 : PHP_SHMOP_GET_RES
220 :
221 3 : if (start < 0 || start > shmop->size) {
222 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
223 0 : RETURN_FALSE;
224 : }
225 :
226 3 : if (start + count > shmop->size || count < 0) {
227 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
228 0 : RETURN_FALSE;
229 : }
230 :
231 3 : startaddr = shmop->addr + start;
232 3 : bytes = count ? count : shmop->size - start;
233 :
234 3 : return_string = emalloc(bytes+1);
235 3 : memcpy(return_string, startaddr, bytes);
236 3 : return_string[bytes] = 0;
237 :
238 3 : RETURN_STRINGL(return_string, bytes, 0);
239 : }
240 : /* }}} */
241 :
242 : /* {{{ proto void shmop_close (int shmid)
243 : closes a shared memory segment */
244 : PHP_FUNCTION(shmop_close)
245 3 : {
246 : long shmid;
247 : struct php_shmop *shmop;
248 : int type;
249 :
250 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
251 0 : return;
252 : }
253 :
254 3 : PHP_SHMOP_GET_RES
255 :
256 3 : zend_list_delete(shmid);
257 : }
258 : /* }}} */
259 :
260 : /* {{{ proto int shmop_size (int shmid)
261 : returns the shm size */
262 : PHP_FUNCTION(shmop_size)
263 1 : {
264 : long shmid;
265 : struct php_shmop *shmop;
266 : int type;
267 :
268 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
269 0 : return;
270 : }
271 :
272 1 : PHP_SHMOP_GET_RES
273 :
274 1 : RETURN_LONG(shmop->size);
275 : }
276 : /* }}} */
277 :
278 : /* {{{ proto int shmop_write (int shmid, string data, int offset)
279 : writes to a shared memory segment */
280 : PHP_FUNCTION(shmop_write)
281 3 : {
282 : struct php_shmop *shmop;
283 : int type;
284 : int writesize;
285 : long shmid, offset;
286 : char *data;
287 : int data_len;
288 :
289 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
290 0 : return;
291 : }
292 :
293 3 : PHP_SHMOP_GET_RES
294 :
295 3 : if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
296 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
297 1 : RETURN_FALSE;
298 : }
299 :
300 2 : if (offset < 0 || offset > shmop->size) {
301 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
302 0 : RETURN_FALSE;
303 : }
304 :
305 2 : writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
306 2 : memcpy(shmop->addr + offset, data, writesize);
307 :
308 2 : RETURN_LONG(writesize);
309 : }
310 : /* }}} */
311 :
312 : /* {{{ proto bool shmop_delete (int shmid)
313 : mark segment for deletion */
314 : PHP_FUNCTION(shmop_delete)
315 1 : {
316 : long shmid;
317 : struct php_shmop *shmop;
318 : int type;
319 :
320 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
321 0 : return;
322 : }
323 :
324 1 : PHP_SHMOP_GET_RES
325 :
326 1 : if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
327 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
328 0 : RETURN_FALSE;
329 : }
330 :
331 1 : RETURN_TRUE;
332 : }
333 : /* }}} */
334 :
335 : #endif /* HAVE_SHMOP */
336 :
337 : /*
338 : * Local variables:
339 : * tab-width: 4
340 : * c-basic-offset: 4
341 : * End:
342 : * vim600: sw=4 ts=4 fdm=marker
343 : * vim<600: sw=4 ts=4
344 : */
|