1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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 : | Author: Jason Greene <jason@inetgurus.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: pcntl.c 281178 2009-05-26 14:02:34Z lbarnaud $ */
20 :
21 : #define PCNTL_DEBUG 0
22 :
23 : #if PCNTL_DEBUG
24 : #define DEBUG_OUT printf("DEBUG: ");printf
25 : #define IF_DEBUG(z) z
26 : #else
27 : #define IF_DEBUG(z)
28 : #endif
29 :
30 : #ifdef HAVE_CONFIG_H
31 : #include "config.h"
32 : #endif
33 :
34 : #include "php.h"
35 : #include "php_ini.h"
36 : #include "ext/standard/info.h"
37 : #include "php_pcntl.h"
38 :
39 : #if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
40 : #include <sys/time.h>
41 : #include <sys/resource.h>
42 : #endif
43 :
44 : ZEND_DECLARE_MODULE_GLOBALS(pcntl)
45 : static PHP_GINIT_FUNCTION(pcntl);
46 :
47 : zend_function_entry pcntl_functions[] = {
48 : PHP_FE(pcntl_fork, NULL)
49 : PHP_FE(pcntl_waitpid, second_arg_force_ref)
50 : PHP_FE(pcntl_wait, first_arg_force_ref)
51 : PHP_FE(pcntl_signal, NULL)
52 : PHP_FE(pcntl_wifexited, NULL)
53 : PHP_FE(pcntl_wifstopped, NULL)
54 : PHP_FE(pcntl_wifsignaled, NULL)
55 : PHP_FE(pcntl_wexitstatus, NULL)
56 : PHP_FE(pcntl_wtermsig, NULL)
57 : PHP_FE(pcntl_wstopsig, NULL)
58 : PHP_FE(pcntl_exec, NULL)
59 : PHP_FE(pcntl_alarm, NULL)
60 : #ifdef HAVE_GETPRIORITY
61 : PHP_FE(pcntl_getpriority, NULL)
62 : #endif
63 : #ifdef HAVE_SETPRIORITY
64 : PHP_FE(pcntl_setpriority, NULL)
65 : #endif
66 : {NULL, NULL, NULL}
67 : };
68 :
69 : zend_module_entry pcntl_module_entry = {
70 : STANDARD_MODULE_HEADER,
71 : "pcntl",
72 : pcntl_functions,
73 : PHP_MINIT(pcntl),
74 : PHP_MSHUTDOWN(pcntl),
75 : PHP_RINIT(pcntl),
76 : PHP_RSHUTDOWN(pcntl),
77 : PHP_MINFO(pcntl),
78 : NO_VERSION_YET,
79 : PHP_MODULE_GLOBALS(pcntl),
80 : PHP_GINIT(pcntl),
81 : NULL,
82 : NULL,
83 : STANDARD_MODULE_PROPERTIES_EX
84 : };
85 :
86 : #ifdef COMPILE_DL_PCNTL
87 : ZEND_GET_MODULE(pcntl)
88 : # ifdef PHP_WIN32
89 : # include "zend_arg_defs.c"
90 : # endif
91 : #endif
92 :
93 : static void pcntl_signal_handler(int);
94 : static void pcntl_tick_handler();
95 :
96 : void php_register_signal_constants(INIT_FUNC_ARGS)
97 13565 : {
98 :
99 : /* Wait Constants */
100 : #ifdef WNOHANG
101 13565 : REGISTER_LONG_CONSTANT("WNOHANG", (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
102 : #endif
103 : #ifdef WUNTRACED
104 13565 : REGISTER_LONG_CONSTANT("WUNTRACED", (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
105 : #endif
106 :
107 : /* Signal Constants */
108 13565 : REGISTER_LONG_CONSTANT("SIG_IGN", (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
109 13565 : REGISTER_LONG_CONSTANT("SIG_DFL", (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
110 13565 : REGISTER_LONG_CONSTANT("SIG_ERR", (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
111 13565 : REGISTER_LONG_CONSTANT("SIGHUP", (long) SIGHUP, CONST_CS | CONST_PERSISTENT);
112 13565 : REGISTER_LONG_CONSTANT("SIGINT", (long) SIGINT, CONST_CS | CONST_PERSISTENT);
113 13565 : REGISTER_LONG_CONSTANT("SIGQUIT", (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
114 13565 : REGISTER_LONG_CONSTANT("SIGILL", (long) SIGILL, CONST_CS | CONST_PERSISTENT);
115 13565 : REGISTER_LONG_CONSTANT("SIGTRAP", (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
116 13565 : REGISTER_LONG_CONSTANT("SIGABRT", (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
117 : #ifdef SIGIOT
118 13565 : REGISTER_LONG_CONSTANT("SIGIOT", (long) SIGIOT, CONST_CS | CONST_PERSISTENT);
119 : #endif
120 13565 : REGISTER_LONG_CONSTANT("SIGBUS", (long) SIGBUS, CONST_CS | CONST_PERSISTENT);
121 13565 : REGISTER_LONG_CONSTANT("SIGFPE", (long) SIGFPE, CONST_CS | CONST_PERSISTENT);
122 13565 : REGISTER_LONG_CONSTANT("SIGKILL", (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
123 13565 : REGISTER_LONG_CONSTANT("SIGUSR1", (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
124 13565 : REGISTER_LONG_CONSTANT("SIGSEGV", (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
125 13565 : REGISTER_LONG_CONSTANT("SIGUSR2", (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
126 13565 : REGISTER_LONG_CONSTANT("SIGPIPE", (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
127 13565 : REGISTER_LONG_CONSTANT("SIGALRM", (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
128 13565 : REGISTER_LONG_CONSTANT("SIGTERM", (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
129 : #ifdef SIGSTKFLT
130 13565 : REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
131 : #endif
132 : #ifdef SIGCLD
133 13565 : REGISTER_LONG_CONSTANT("SIGCLD", (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
134 : #endif
135 : #ifdef SIGCHLD
136 13565 : REGISTER_LONG_CONSTANT("SIGCHLD", (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
137 : #endif
138 13565 : REGISTER_LONG_CONSTANT("SIGCONT", (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
139 13565 : REGISTER_LONG_CONSTANT("SIGSTOP", (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
140 13565 : REGISTER_LONG_CONSTANT("SIGTSTP", (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
141 13565 : REGISTER_LONG_CONSTANT("SIGTTIN", (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
142 13565 : REGISTER_LONG_CONSTANT("SIGTTOU", (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
143 13565 : REGISTER_LONG_CONSTANT("SIGURG", (long) SIGURG , CONST_CS | CONST_PERSISTENT);
144 13565 : REGISTER_LONG_CONSTANT("SIGXCPU", (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
145 13565 : REGISTER_LONG_CONSTANT("SIGXFSZ", (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
146 13565 : REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
147 13565 : REGISTER_LONG_CONSTANT("SIGPROF", (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
148 13565 : REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
149 : #ifdef SIGPOLL
150 13565 : REGISTER_LONG_CONSTANT("SIGPOLL", (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
151 : #endif
152 13565 : REGISTER_LONG_CONSTANT("SIGIO", (long) SIGIO, CONST_CS | CONST_PERSISTENT);
153 : #ifdef SIGPWR
154 13565 : REGISTER_LONG_CONSTANT("SIGPWR", (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
155 : #endif
156 : #ifdef SIGSYS
157 13565 : REGISTER_LONG_CONSTANT("SIGSYS", (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
158 13565 : REGISTER_LONG_CONSTANT("SIGBABY", (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
159 : #endif
160 :
161 : #if HAVE_GETPRIORITY || HAVE_SETPRIORITY
162 13565 : REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
163 13565 : REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
164 13565 : REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
165 : #endif
166 13565 : }
167 :
168 : static PHP_GINIT_FUNCTION(pcntl)
169 13565 : {
170 13565 : memset(pcntl_globals, 0, sizeof(*pcntl_globals));
171 13565 : }
172 :
173 : PHP_RINIT_FUNCTION(pcntl)
174 13551 : {
175 13551 : zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
176 13551 : PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
177 13551 : return SUCCESS;
178 : }
179 :
180 : PHP_MINIT_FUNCTION(pcntl)
181 13565 : {
182 13565 : php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
183 13565 : php_add_tick_function(pcntl_tick_handler);
184 :
185 13565 : return SUCCESS;
186 : }
187 :
188 : PHP_MSHUTDOWN_FUNCTION(pcntl)
189 13598 : {
190 13598 : return SUCCESS;
191 : }
192 :
193 : PHP_RSHUTDOWN_FUNCTION(pcntl)
194 13584 : {
195 : struct php_pcntl_pending_signal *sig;
196 :
197 : /* FIXME: if a signal is delivered after this point, things will go pear shaped;
198 : * need to remove signal handlers */
199 13584 : zend_hash_destroy(&PCNTL_G(php_signal_table));
200 27168 : while (PCNTL_G(head)) {
201 0 : sig = PCNTL_G(head);
202 0 : PCNTL_G(head) = sig->next;
203 0 : efree(sig);
204 : }
205 27168 : while (PCNTL_G(spares)) {
206 0 : sig = PCNTL_G(spares);
207 0 : PCNTL_G(spares) = sig->next;
208 0 : efree(sig);
209 : }
210 13584 : return SUCCESS;
211 : }
212 :
213 : PHP_MINFO_FUNCTION(pcntl)
214 6 : {
215 6 : php_info_print_table_start();
216 6 : php_info_print_table_header(2, "pcntl support", "enabled");
217 6 : php_info_print_table_end();
218 6 : }
219 :
220 : /* {{{ proto int pcntl_fork(void)
221 : Forks the currently running process following the same behavior as the UNIX fork() system call*/
222 : PHP_FUNCTION(pcntl_fork)
223 50 : {
224 : pid_t id;
225 :
226 50 : id = fork();
227 86 : if (id == -1) {
228 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
229 : }
230 :
231 86 : RETURN_LONG((long) id);
232 : }
233 : /* }}} */
234 :
235 : /* {{{ proto int pcntl_alarm(int seconds)
236 : Set an alarm clock for delivery of a signal*/
237 : PHP_FUNCTION(pcntl_alarm)
238 13 : {
239 : long seconds;
240 :
241 13 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
242 0 : return;
243 :
244 13 : RETURN_LONG ((long) alarm(seconds));
245 : }
246 : /* }}} */
247 :
248 : /* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
249 : Waits on or returns the status of a forked child as defined by the waitpid() system call */
250 : PHP_FUNCTION(pcntl_waitpid)
251 19 : {
252 19 : long pid, options = 0;
253 19 : zval *z_status = NULL;
254 : int status;
255 : pid_t child_id;
256 :
257 19 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
258 0 : return;
259 :
260 19 : convert_to_long_ex(&z_status);
261 :
262 19 : status = Z_LVAL_P(z_status);
263 :
264 19 : child_id = waitpid((pid_t) pid, &status, options);
265 :
266 19 : Z_LVAL_P(z_status) = status;
267 :
268 19 : RETURN_LONG((long) child_id);
269 : }
270 : /* }}} */
271 :
272 : /* {{{ proto int pcntl_wait(int &status)
273 : Waits on or returns the status of a forked child as defined by the waitpid() system call */
274 : PHP_FUNCTION(pcntl_wait)
275 3 : {
276 3 : long options = 0;
277 3 : zval *z_status = NULL;
278 : int status;
279 : pid_t child_id;
280 :
281 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
282 0 : return;
283 :
284 3 : convert_to_long_ex(&z_status);
285 :
286 3 : status = Z_LVAL_P(z_status);
287 : #ifdef HAVE_WAIT3
288 3 : if(options) {
289 0 : child_id = wait3(&status, options, NULL);
290 : }
291 : else {
292 3 : child_id = wait(&status);
293 : }
294 : #else
295 : child_id = wait(&status);
296 : #endif
297 3 : Z_LVAL_P(z_status) = status;
298 :
299 3 : RETURN_LONG((long) child_id);
300 : }
301 : /* }}} */
302 :
303 : /* {{{ proto bool pcntl_wifexited(int status)
304 : Returns true if the child status code represents a successful exit */
305 : PHP_FUNCTION(pcntl_wifexited)
306 1 : {
307 : #ifdef WIFEXITED
308 : zval **status;
309 : int status_word;
310 :
311 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
312 0 : WRONG_PARAM_COUNT;
313 : }
314 :
315 1 : status_word = (int) Z_LVAL_PP(status);
316 :
317 1 : if (WIFEXITED(status_word)) RETURN_TRUE;
318 : #endif
319 0 : RETURN_FALSE;
320 : }
321 : /* }}} */
322 :
323 : /* {{{ proto bool pcntl_wifstopped(int status)
324 : Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
325 : PHP_FUNCTION(pcntl_wifstopped)
326 1 : {
327 : #ifdef WIFSTOPPED
328 : zval **status;
329 : int status_word;
330 :
331 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
332 0 : WRONG_PARAM_COUNT;
333 : }
334 :
335 1 : status_word = (int) Z_LVAL_PP(status);
336 :
337 1 : if (WIFSTOPPED(status_word)) RETURN_TRUE;
338 : #endif
339 0 : RETURN_FALSE;
340 : }
341 : /* }}} */
342 :
343 : /* {{{ proto bool pcntl_wifsignaled(int status)
344 : Returns true if the child status code represents a process that was terminated due to a signal */
345 : PHP_FUNCTION(pcntl_wifsignaled)
346 1 : {
347 : #ifdef WIFSIGNALED
348 : zval **status;
349 : int status_word;
350 :
351 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
352 0 : WRONG_PARAM_COUNT;
353 : }
354 :
355 1 : status_word = (int) Z_LVAL_PP(status);
356 :
357 1 : if (WIFSIGNALED(status_word)) RETURN_TRUE;
358 : #endif
359 0 : RETURN_FALSE;
360 : }
361 : /* }}} */
362 :
363 : /* {{{ proto int pcntl_wexitstatus(int status)
364 : Returns the status code of a child's exit */
365 : PHP_FUNCTION(pcntl_wexitstatus)
366 2 : {
367 : #ifdef WEXITSTATUS
368 : zval **status;
369 : int status_word;
370 :
371 2 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
372 0 : WRONG_PARAM_COUNT;
373 : }
374 :
375 2 : status_word = (int) Z_LVAL_PP(status);
376 :
377 2 : RETURN_LONG(WEXITSTATUS(status_word));
378 : #else
379 : RETURN_FALSE;
380 : #endif
381 : }
382 : /* }}} */
383 :
384 : /* {{{ proto int pcntl_wtermsig(int status)
385 : Returns the number of the signal that terminated the process who's status code is passed */
386 : PHP_FUNCTION(pcntl_wtermsig)
387 1 : {
388 : #ifdef WTERMSIG
389 : zval **status;
390 : int status_word;
391 :
392 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
393 0 : WRONG_PARAM_COUNT;
394 : }
395 :
396 1 : status_word = (int) Z_LVAL_PP(status);
397 :
398 1 : RETURN_LONG(WTERMSIG(status_word));
399 : #else
400 : RETURN_FALSE;
401 : #endif
402 : }
403 : /* }}} */
404 :
405 : /* {{{ proto int pcntl_wstopsig(int status)
406 : Returns the number of the signal that caused the process to stop who's status code is passed */
407 : PHP_FUNCTION(pcntl_wstopsig)
408 1 : {
409 : #ifdef WSTOPSIG
410 : zval **status;
411 : int status_word;
412 :
413 1 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
414 0 : WRONG_PARAM_COUNT;
415 : }
416 :
417 1 : status_word = (int) Z_LVAL_PP(status);
418 :
419 1 : RETURN_LONG(WSTOPSIG(status_word));
420 : #else
421 : RETURN_FALSE;
422 : #endif
423 : }
424 : /* }}} */
425 :
426 : /* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
427 : Executes specified program in current process space as defined by exec(2) */
428 : PHP_FUNCTION(pcntl_exec)
429 0 : {
430 : zval *args, *envs;
431 : zval **element;
432 : HashTable *args_hash, *envs_hash;
433 0 : int argc = 0, argi = 0;
434 0 : int envc = 0, envi = 0;
435 0 : int return_val = 0;
436 0 : char **argv = NULL, **envp = NULL;
437 : char **current_arg, **pair;
438 : int pair_length;
439 : char *key;
440 : int key_length;
441 : char *path;
442 : int path_len;
443 : long key_num;
444 :
445 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) {
446 0 : return;
447 : }
448 :
449 0 : if (ZEND_NUM_ARGS() > 1) {
450 : /* Build argumnent list */
451 0 : args_hash = HASH_OF(args);
452 0 : argc = zend_hash_num_elements(args_hash);
453 :
454 0 : argv = safe_emalloc((argc + 2), sizeof(char *), 0);
455 0 : *argv = path;
456 0 : for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
457 0 : (argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
458 0 : (argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
459 :
460 0 : convert_to_string_ex(element);
461 0 : *current_arg = Z_STRVAL_PP(element);
462 : }
463 0 : *(current_arg) = NULL;
464 : } else {
465 0 : argv = emalloc(2 * sizeof(char *));
466 0 : *argv = path;
467 0 : *(argv+1) = NULL;
468 : }
469 :
470 0 : if ( ZEND_NUM_ARGS() == 3 ) {
471 : /* Build environment pair list */
472 0 : envs_hash = HASH_OF(envs);
473 0 : envc = zend_hash_num_elements(envs_hash);
474 :
475 0 : envp = safe_emalloc((envc + 1), sizeof(char *), 0);
476 0 : for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
477 0 : (envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
478 0 : (envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
479 0 : switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
480 : case HASH_KEY_IS_LONG:
481 0 : key = emalloc(101);
482 0 : snprintf(key, 100, "%ld", key_num);
483 0 : key_length = strlen(key);
484 0 : break;
485 : case HASH_KEY_NON_EXISTANT:
486 0 : pair--;
487 0 : continue;
488 : }
489 :
490 0 : convert_to_string_ex(element);
491 :
492 : /* Length of element + equal sign + length of key + null */
493 0 : pair_length = Z_STRLEN_PP(element) + key_length + 2;
494 0 : *pair = emalloc(pair_length);
495 0 : strlcpy(*pair, key, key_length);
496 0 : strlcat(*pair, "=", pair_length);
497 0 : strlcat(*pair, Z_STRVAL_PP(element), pair_length);
498 :
499 : /* Cleanup */
500 0 : if (return_val == HASH_KEY_IS_LONG) efree(key);
501 : }
502 0 : *(pair) = NULL;
503 : }
504 :
505 0 : if (execve(path, argv, envp) == -1) {
506 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
507 : }
508 :
509 : /* Cleanup */
510 0 : if (envp != NULL) {
511 0 : for (pair = envp; *pair != NULL; pair++) efree(*pair);
512 0 : efree(envp);
513 : }
514 :
515 0 : efree(argv);
516 :
517 0 : RETURN_FALSE;
518 : }
519 : /* }}} */
520 :
521 : /* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
522 : Assigns a system signal handler to a PHP function */
523 : PHP_FUNCTION(pcntl_signal)
524 0 : {
525 0 : zval *handle, **dest_handle = NULL;
526 : char *func_name;
527 : long signo;
528 0 : zend_bool restart_syscalls = 1;
529 :
530 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
531 0 : return;
532 : }
533 :
534 0 : if (!PCNTL_G(spares)) {
535 : /* since calling malloc() from within a signal handler is not portable,
536 : * pre-allocate a few records for recording signals */
537 : int i;
538 0 : for (i = 0; i < 32; i++) {
539 : struct php_pcntl_pending_signal *psig;
540 :
541 0 : psig = emalloc(sizeof(*psig));
542 0 : psig->next = PCNTL_G(spares);
543 0 : PCNTL_G(spares) = psig;
544 : }
545 : }
546 :
547 : /* Special long value case for SIG_DFL and SIG_IGN */
548 0 : if (Z_TYPE_P(handle)==IS_LONG) {
549 0 : if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
550 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
551 : }
552 0 : if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
553 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
554 0 : RETURN_FALSE;
555 : }
556 0 : RETURN_TRUE;
557 : }
558 :
559 0 : if (!zend_is_callable(handle, 0, &func_name)) {
560 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
561 0 : efree(func_name);
562 0 : RETURN_FALSE;
563 : }
564 0 : efree(func_name);
565 :
566 : /* Add the function name to our signal table */
567 0 : zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
568 0 : if (dest_handle) zval_add_ref(dest_handle);
569 :
570 0 : if (php_signal(signo, pcntl_signal_handler, (int) restart_syscalls) == SIG_ERR) {
571 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
572 0 : RETURN_FALSE;
573 : }
574 0 : RETURN_TRUE;
575 : }
576 : /* }}} */
577 :
578 : #ifdef HAVE_GETPRIORITY
579 : /* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
580 : Get the priority of any process */
581 : PHP_FUNCTION(pcntl_getpriority)
582 0 : {
583 0 : long who = PRIO_PROCESS;
584 0 : long pid = getpid();
585 : int pri;
586 :
587 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
588 0 : RETURN_FALSE;
589 : }
590 :
591 : /* needs to be cleared, since any returned value is valid */
592 0 : errno = 0;
593 :
594 0 : pri = getpriority(who, pid);
595 :
596 0 : if (errno) {
597 0 : switch (errno) {
598 : case ESRCH:
599 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
600 0 : break;
601 : case EINVAL:
602 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
603 0 : break;
604 : default:
605 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
606 : break;
607 : }
608 0 : RETURN_FALSE;
609 : }
610 :
611 0 : RETURN_LONG(pri);
612 : }
613 : /* }}} */
614 : #endif
615 :
616 : #ifdef HAVE_SETPRIORITY
617 : /* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
618 : Change the priority of any process */
619 : PHP_FUNCTION(pcntl_setpriority)
620 0 : {
621 0 : long who = PRIO_PROCESS;
622 0 : long pid = getpid();
623 : long pri;
624 :
625 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
626 0 : RETURN_FALSE;
627 : }
628 :
629 0 : if (setpriority(who, pid, pri)) {
630 0 : switch (errno) {
631 : case ESRCH:
632 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
633 0 : break;
634 : case EINVAL:
635 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
636 0 : break;
637 : case EPERM:
638 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: A process was located, but neither its effective nor real user ID matched the effective user ID of the caller", errno);
639 0 : break;
640 : case EACCES:
641 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
642 0 : break;
643 : default:
644 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
645 : break;
646 : }
647 0 : RETURN_FALSE;
648 : }
649 :
650 0 : RETURN_TRUE;
651 : }
652 : /* }}} */
653 : #endif
654 :
655 : /* Our custom signal handler that calls the appropriate php_function */
656 : static void pcntl_signal_handler(int signo)
657 0 : {
658 : struct php_pcntl_pending_signal *psig;
659 : TSRMLS_FETCH();
660 :
661 0 : psig = PCNTL_G(spares);
662 0 : if (!psig) {
663 : /* oops, too many signals for us to track, so we'll forget about this one */
664 0 : return;
665 : }
666 0 : PCNTL_G(spares) = psig->next;
667 :
668 0 : psig->signo = signo;
669 0 : psig->next = NULL;
670 :
671 : /* the head check is important, as the tick handler cannot atomically clear both
672 : * the head and tail */
673 0 : if (PCNTL_G(head) && PCNTL_G(tail)) {
674 0 : PCNTL_G(tail)->next = psig;
675 : } else {
676 0 : PCNTL_G(head) = psig;
677 : }
678 0 : PCNTL_G(tail) = psig;
679 : }
680 :
681 : void pcntl_tick_handler()
682 5 : {
683 : zval *param, **handle, *retval;
684 : struct php_pcntl_pending_signal *queue, *next;
685 : TSRMLS_FETCH();
686 :
687 : /* Bail if the queue is empty or if we are already playing the queue*/
688 5 : if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue))
689 5 : return;
690 :
691 : /* Prevent reentrant handler calls */
692 0 : PCNTL_G(processing_signal_queue) = 1;
693 :
694 0 : queue = PCNTL_G(head);
695 0 : PCNTL_G(head) = NULL; /* simple stores are atomic */
696 :
697 : /* Allocate */
698 :
699 0 : while (queue) {
700 0 : if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
701 0 : MAKE_STD_ZVAL(retval);
702 0 : MAKE_STD_ZVAL(param);
703 0 : ZVAL_NULL(retval);
704 0 : ZVAL_LONG(param, queue->signo);
705 :
706 : /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
707 : /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
708 0 : call_user_function(EG(function_table), NULL, *handle, retval, 1, ¶m TSRMLS_CC);
709 0 : zval_ptr_dtor(¶m);
710 0 : zval_ptr_dtor(&retval);
711 : }
712 :
713 0 : next = queue->next;
714 0 : queue->next = PCNTL_G(spares);
715 0 : PCNTL_G(spares) = queue;
716 0 : queue = next;
717 : }
718 :
719 : /* Re-enable queue */
720 0 : PCNTL_G(processing_signal_queue) = 0;
721 : }
722 :
723 :
724 :
725 : /*
726 : * Local variables:
727 : * tab-width: 4
728 : * c-basic-offset: 4
729 : * indent-tabs-mode: t
730 : * End:
731 : */
|